Skip to content

Troubleshooting

Troubleshooting

Diagnose Olivares AI startup, source ingestion, hook enforcement, audit-chain integrity, health probes and demo-mode escape.

Last updated:

Diagnostic notes for the issues operators hit most often. Each section states the symptom, the cause, and the fix. For the full flag and environment-variable surface see the CLI reference and configuration.

Engine won’t start

TLS certificate generation fails

Symptom: the engine exits on boot with a write error referencing the data directory.

With no --tls-cert/--tls-key supplied, the engine generates a self-signed certificate in the data directory before any listener accepts a connection. If the data directory is read-only or does not exist, the write fails and the process exits.

Fix: ensure the path given by --data-dir (or OLIVARES_DATA_DIR, falling back to ./olivares-data) points to a writable, persistent directory. Alternatively, supply your own certificate with --tls-cert and --tls-key so no generation is attempted.

Postgres role is privileged

Symptom: the engine exits with a message about a superuser or BYPASSRLS role.

The Postgres store enforces tenant isolation with FORCE ROW LEVEL SECURITY. A superuser or BYPASSRLS role silently bypasses all RLS policies, so the engine refuses to start against one.

Fix: provision a dedicated least-privilege role (NOSUPERUSER NOBYPASSRLS NOCREATEROLE NOCREATEDB) that owns its database. If you genuinely need to override the guard in a single-tenant or throwaway environment, pass --allow-privileged-db-role. See self-host for the full Postgres setup.

—seed-demo on a non-loopback bind

Symptom: the engine exits with an error directing you to bind 127.0.0.1.

--seed-demo provisions a demo administrator whose password is public (it lives in the source tree). The engine refuses to start if either --listen or --grpc-listen is bound to a non-loopback address.

Fix: bind loopback (127.0.0.1) or remove --seed-demo. Demo mode is for local walkthroughs only — see the quickstart.

Missing or unwritable data directory

Symptom: the engine exits referencing a missing path or permission error.

The data directory holds the SQLite store (when using the default engine), the audit signing key, and TLS material. It must exist and be writable before boot.

Fix: create the directory with restrictive permissions and point --data-dir or OLIVARES_DATA_DIR at it. For containerised deploys, mount a persistent volume.

Sources not producing edges

OLIVARES_SOURCES_CONFIG is unset

Symptom: the engine starts, the boot log warns that no sources are configured, and the access map stays empty.

Without OLIVARES_SOURCES_CONFIG the engine runs with no source connectors. It does not crash — it warns honestly and continues.

Fix: set OLIVARES_SOURCES_CONFIG to the path of your sources JSON file. See connect a source.

Invalid JSON in the config file

Symptom: the boot log warns about an unreadable or invalid config; no sources register.

The engine warns and continues with an empty source list on any JSON parse error. It does not abort the boot.

Fix: validate the file with jq . < "$OLIVARES_SOURCES_CONFIG" and fix any syntax errors. Re-read the engine’s boot log — the warning includes the parse error.

Wrong source kind string

Symptom: a configured source does not resolve; the boot log warns that the kind is unknown.

The registered source kinds are exact strings: pgaudit, s3cloudtrail, ebpf, runtime, mcp, claude. Earlier documentation that used pg_audit or cloudtrail was wrong — those strings do not resolve.

Fix: use the exact kind values listed above. If a kind you expect is missing, it may not be wired into the stock serve binary yet. Confirm against the connector’s own descriptor.

Log file not readable

Symptom: the source registers but emits no observations; the log reports a permission or file-not-found error.

The pgaudit connector reads the PostgreSQL log file; the s3cloudtrail connector reads CloudTrail log files or a directory of them. Both require read access from the process running the engine or collector.

Fix: check permissions on the log_path (pgaudit) or path (s3cloudtrail) value. For containerised deploys, verify the volume mount is correct and the file exists at the expected path inside the container.

pgaudit follow with csvlog format

Symptom: a pgaudit source with "follow": "true" and "format": "csvlog" does not tail continuously — it runs as a batch.

follow only works with jsonlog. A csvlog file is always read as a batch because its records can span newlines, which makes reliable tail-following unsafe.

Fix: switch the PostgreSQL log format to jsonlog if you need continuous tailing. Otherwise accept the batch behaviour and optionally set poll_seconds on the source entry to control re-read frequency.

Claude Code hooks not firing

Managed settings not deployed

Symptom: Claude Code runs with no hook interposition; tool calls are unobserved and ungoverned.

The enforcement hooks ship in Claude Code’s enterprise managed-settings tier. If the managed-settings file is not present on the host, the hooks are simply absent.

Fix: verify the managed-settings file is deployed to the correct path on every host where Claude Code runs. With managed-hooks-only enabled, a developer cannot disable or replace the hook from a lower-precedence settings file.

ANTHROPIC_BASE_URL override

Symptom: hooks are deployed but Claude Code bypasses them entirely.

A custom ANTHROPIC_BASE_URL can bypass server-managed-settings, which means the managed hooks never load. This is a documented honest caveat of the cooperative path — the connector cannot enforce against a client that opts out of the settings tier.

Fix: ensure ANTHROPIC_BASE_URL is not set, or that the custom endpoint still honours managed settings. For non-cooperative agents the kernel/eBPF backstop is the ground truth, not hooks.

Hook PEP unreachable

Symptom: all tool calls are denied; the hook returns a clean deny for every request.

The PEP is deny-closed: if the enforcement point is unreachable — network partition, wrong address, process down — every tool call is denied. The verdict’s zero value is itself a deny. This is deliberate asymmetric-risk design.

Fix: check loopback connectivity to the PEP address. Verify the engine is running and the HTTP listener is healthy (/livez). If the PEP is intentionally down, the lighter local enforcement mode (no engine round-trip) avoids wedging developers while the control plane is offline, but it must be explicitly configured.

Audit chain verification failures

Key mismatch

Symptom: olivares audit verify exits non-zero; the report shows a signature verification failure.

The --pubkey or --event-pubkey flag points to a public key that does not match the signing key that wrote the checkpoints. This is common after a key rotation or when verifying against the wrong off-box key copy.

Fix: use the public key that corresponds to the signing key active during the period you are verifying. The engine logs the key fingerprint at boot.

Chain gap after data-directory replacement

Symptom: olivares audit verify reports a chain gap — the stored chain tips do not match the ledger entries.

If the data directory was replaced (for example, restored from a filesystem snapshot rather than olivares dr restore) the chain tips may not align with the ledger.

Fix: use olivares dr verify for a non-destructive DR drill that checks ledger continuity after a restore. olivares dr restore is the ledger-continuity-safe restore path — it re-verifies the chain on restore and exits non-zero unless the ledger is green.

Multiple nodes with different signing keys

Symptom: the ledger forks at failover; verification passes on one node’s checkpoints but fails on the other’s.

In an active-passive cluster, each node mints its own signing key on first boot if none is shared. After failover the new leader signs with a different key, forking the chain.

Fix: share the signing key across replicas via OLIVARES_AUDIT_SIGNING_KEY_FILE (a mounted secret) or OLIVARES_AUDIT_SIGNING_KEY (base64 inline, less preferred). See the configuration reference for key custody.

Health probe issues

/readyz returns 503 with “store”:“down”

Symptom: the readiness probe fails; the body includes "store":"down".

The store ping ran with a short timeout and failed. The instance drains rather than hanging on a wedged backend.

Fix: check database connectivity. For Postgres, verify the DSN, network path, and that the database process is running. For SQLite, check that the store file in the data directory is not locked or corrupt.

/readyz returns 503 with “leader”:false

Symptom: the readiness probe returns 503; the body includes "leader":false.

This is expected in an active-passive cluster. A standby reports 503 on /readyz so the load balancer stops routing traffic to it, without restarting it. When the leader dies, the standby acquires leadership and /readyz flips to 200.

Fix: no fix needed — this is correct behaviour. Ensure your load balancer routes on /readyz (readiness) and your orchestrator restarts on /livez (liveness). Do not confuse the two or you will get restart loops on a healthy standby.

/livez fails

Symptom: the liveness probe returns an error or times out.

/livez runs no dependency check. If it fails, the process itself is unhealthy — not a downstream dependency.

Fix: check system resources (memory, disk, file descriptors) and the engine’s logs. A restart is appropriate here, unlike a /readyz failure.

Demo mode issues

Demo credentials are public

The demo administrator password is in the source tree on purpose — it is not a secret. Always use a throwaway data directory with --seed-demo and never expose the demo to a network.

Transitioning from demo to production

Do not reuse a demo data directory. The demo seeds fabricated data and a public credential. Start fresh: run olivares serve without --seed-demo, claim the one-time setup token, and create a real administrator. See self-host.

PDP configuration issues

Invalid Cedar policy file

Symptom: the boot log warns that the external PDP is disabled; the engine continues with native ABAC and RBAC only.

If OLIVARES_PDP_ENGINE=cedar but OLIVARES_PDP_CEDAR_FILE points to an unreadable or malformed file, the engine disables the external PDP. It does not crash and does not leave requests un-governed — the native engine keeps enforcing.

Fix: check the file path and validate the Cedar policy syntax. The boot log includes the specific error.

OPA endpoint unreachable

Symptom: same as above — external PDP disabled, native RBAC keeps governing.

If OLIVARES_PDP_ENGINE=opa but OLIVARES_PDP_OPA_URL is unreachable or returns errors, the engine falls back to native enforcement. A broken external PDP never opens the gate.

Fix: verify the OPA URL, network path, and bearer token (OLIVARES_PDP_OPA_TOKEN). Confirm the OPA service is running and the decision path (OLIVARES_PDP_OPA_PATH) is correct.

Both PDP engines configured

Symptom: unexpected policy evaluation; unclear which engine is active.

OLIVARES_PDP_ENGINE selects exactly one engine: cedar or opa. Setting conflicting variables for both engines alongside an ambiguous or missing engine selector leads to unpredictable PDP state.

Fix: set OLIVARES_PDP_ENGINE to exactly one value and configure only that engine’s variables. Remove the other engine’s environment variables to avoid confusion.

Search documentation