Documentation menu

Troubleshooting

locac tries to fail with a sentence you can act on rather than a stack trace. This page is the index: the message on the left, what it means and what to do on the right.

The run will not start

error: --model is required.

run and resume never guess a model. Pass one, or set a default in the config file so you stop typing it:

locac run "" --provider anthropic --model claude-opus-4-8
{ "provider": "anthropic", "model": "claude-opus-4-8" }

error: Provide either --provider … or --api …

error: Provide either --provider <name> --model <id>, or --api <api> --base-url <url> --model <id>.

You gave a model but no way to reach it. Either name a built-in provider, or describe an endpoint yourself with --api and --base-url. Mixing halves of the two forms is what triggers this.

Unknown provider "…"

The name is not a built-in and is not a saved custom provider. locac config show lists what is actually configured. See Providers.

A missing API key is not a startup error

Nothing at startup checks that a key exists. A run with no key starts, sends its first request, and fails with an authentication error from the provider. If a run dies immediately on its first turn with an auth failure, check the key before anything else: apiKey, the $VAR it expands to, or the provider's environment variable.

A "$MY_KEY" value whose variable is unset resolves to nothing, deliberately: locac would rather fail loudly than send an empty key and get a confusing 401.

error: unknown tool "…"

error: unknown tool "raed" in --tools (known: bash, code_search, coverage, …)

A typo in --tools or --exclude-tools is a startup error, not a silent no-op. The full list of valid names is in the Tool reference.

The same rule applies to a role in your config: every role's tool allow-list is validated at load, so a typo fails before the run rather than halfway through it, at spawn time:

Role "docs-reader" names unknown tool "raed". Known: bash, code_search, coverage, …

See Skills & roles.

error: invalid --<flag> "…"

error: invalid --keep-recent "abc" (want a positive integer)
error: invalid --port "http" (want an integer 1–65535)

Numeric flags are parsed and range-checked at startup. There is no silent fallback to a default.

The sandbox is not what you expected

locac: sandbox=direct — NO OS confinement.

locac: sandbox=direct — NO OS confinement. Target code runs with cwd pinned to the root only.
  why: <the host's own reason>
  use --require-sandbox to refuse to start unconfined.

The run has started, but bash and execute are running the target's code with your privileges. The why: line is the host's actual reason. The common ones:

ReasonFix
The backend is not installedWindows: npx sandbox-runtime windows-install. Linux: install bwrap (bubblewrap), socat and ripgrep.
a no-op command through it failed (exit 1) on Ubuntu 24.04+kernel.apparmor_restrict_unprivileged_userns=1 blocks the nested user namespace. Either relax that sysctl or accept direct.
The probe timed outThe sandbox wedged. The probe is capped at 20 seconds so startup is not held hostage.

Per-OS prerequisites are in Installation.

error: --require-sandbox: no OS sandbox on this host

That is the flag doing its job: it turns the notice above into a refusal to start. Exit code 1.

locac: sandbox=os — unix-socket blocking off …

locac: sandbox=os — unix-socket blocking off: no apply-seccomp, AF_UNIX egress is not confined.

A partial sandbox on Linux. Filesystem and network confinement are in place; the seccomp stage that blocks AF_UNIX is missing, so confined code can still reach host sockets, such as a system bus socket, a container runtime socket. Usually this means the seccomp helper binary could not be resolved. Treat the run as confined-but-not-fully and do not point it at a repository you would not otherwise run.

Why locac can tell you this at all, and why the verdict is measured rather than assumed, is in the Security model.

A dangerous tool call was silently denied

"Ask" with nothing to ask is deny. A piped, --print, or CI run has no interactive terminal, so every dangerous call fails closed. Pass --auto for read-only shell commands, or --yes to approve everything, knowing what that means. The table of what resolves how is in the Tool reference.

Runtime asset problems

locac selftest

Four checks, then selftest: OK or selftest: FAILED with exit 0 or 1:

CheckA failure means
tree-sitter parses a sample and returns call sitesThe compiled build lost its grammar assets. outline, grok_sink and trace_callers will be blind.
At least two bundled skills are readableThe embedded SKILL.md files did not materialise under LOCAC_HOME. Check that directory is writable.
The dashboard shell and client script are embeddedlocac web will serve a broken page.
On Windows, the sandbox helper binary is non-emptyThe Windows sandbox will never engage, and every run falls back to direct.

The OS-sandbox line in the output is a note, not a check: it reports what this host gets and never changes the exit code, because a host without a sandbox is not a broken build.

Run selftest first whenever a compiled binary behaves differently from a development checkout. That difference, a dependency resolving its own vendored binaries from a module URL that, inside a compiled artifact, points at an embedded virtual filesystem, is exactly the class of bug these checks exist to catch.

Provider failures

Every provider error is classified before it is acted on, and the classification decides whether the request is retried.

ClassComes fromRetried
auth401 / 403No. Fix the key
rate_limit429Yes
overloaded408, 409, 529, any 5xx, and a 401/403 whose body says the upstream auth is unavailableYes
networkTransport failureYes
context_overflow400 / 413 / 422 with overflow phrasing in the bodyNo. See below
bad_requestEverything else in the 4xx rangeNo

Retries are 10 attempts by default, backing off from 500 ms to a 30-second ceiling with half-to-full jitter. A Retry-After header is honoured as a floor, not a replacement, and it is capped at 60 seconds, so a provider cannot park your run for an hour.

One rule matters more than the numbers: a request is only retried while nothing durable has been forwarded. Once assistant text has reached you, retrying would duplicate it. Thinking and reasoning tokens do not count as durable, so a turn that has only reasoned so far is still retryable.

The stream stopped mid-response

provider closed the response stream before completing (no finish_reason) — the endpoint/proxy
dropped its upstream connection mid-response (e.g. upstream auth unavailable or a disconnected
stream). Retried automatically; if it persists the provider's upstream is unavailable, not the
request

locac detects a truncated SSE stream, with no finish_reason and no usage record, and retries it. If it persists, the problem is on the provider's side of the wire, not in your request.

Some endpoints legitimately never send finish_reason. There is a per-provider flag to disable truncation detection for those, and it should stay off unless you have measured that endpoint: turning it on means a genuinely truncated response is accepted as a complete one.

context_overflow

The request was larger than the model's window. Compaction normally prevents this; when it does not:

  • Check you are not running with --no-compaction.
  • Check the configured context window matches the model. A --context-window of zero or less is ignored rather than applied.
  • After an overflow, compaction escalates one tier for the rest of the session and stays there. There is no third tier. See Context & compaction.

Sessions

session … has N child fork(s); delete them first

session 4f1c8a20 has 2 child fork(s); delete them first

Deleting a session that other sessions branched from would orphan them, so it is refused. Delete the leaves first.

No session "…"

The id does not exist in the database this command opened. The database lives under LOCAC_HOME, not in the target repository. If you are pointing --db somewhere else, or have set LOCAC_HOME differently between runs, you are looking at a different store.

If you used a build old enough to have written sessions inside the target root, locac says so once at startup rather than silently adopting a store the target repository could have rewritten.

See Sessions.

A resumed pre-0.5.2 finding is refused at High or Critical

Cannot promote finding f_…: it has no semantic execution proof bound to this file/URL.

0.5.2 made a proof artifact carry a structured claim and a checked assertion. Artifacts recorded before that release have neither, and they are not grandfathered: the schema migration adds the two columns and loses no data, but an old row stays a diagnostic. The evidence is still in the database and still readable; it just cannot promote a severity any more.

Re-run the proof under the current gate - reproduce with a claim matching the finding's location, a run_module detection, or replay_request with a differential assertion - and attach the new artifact with record_finding(artifact_ref=…). This is deliberate: the point of the release was that "a command ran and exited zero" was being accepted as proof of exploitability, and honouring the old rows would keep exactly that class of finding alive.

Releases and upgrading has the rest of what 0.5.2 changed under you.

Skills and roles

A skill does not appear

Discovery is quiet by design: an unparseable file is skipped, not fatal. In order of likelihood:

  1. CRLF line endings in the front matter. This was a real bug: a SKILL.md authored on Windows parsed as having no front matter at all and the skill vanished. Current builds split on both, but a stale binary will not.
  2. Wrong depth. The glob is exactly */SKILL.md, one level under the skills directory. A skill nested deeper is invisible, deliberately.
  3. Missing name or description. Both are required; without either it is not a skill.
  4. An unsafe name. Unsafe skill name "…" — use letters, digits, _ or -.

locac skills list shows what was actually discovered, tagged [user] or [bundled].

no user skill named "…"

no user skill named "x" (add it first; bundled skills aren't editable in place)

locac skills edit only edits skills in your own directory. Bundled skills ship inside the binary; to modify one, add a user skill with the same name, which overrides the bundled one.

The dashboard

ResponseMeaning
refusing to bind <host> without auth — the dashboard can launch bash. …You asked for a non-loopback bind with no password and JWT secret configured. Set both, or bind 127.0.0.1.
forbidden host (403)The Host header did not match the bind. Usually a reverse proxy or a custom hostname. The guard exists to stop DNS rebinding, so it will not be relaxed.
bad csrf token (403)The request did not carry the per-startup CSRF header. Reload the page: the token is minted at startup, so a tab left open across a restart holds a stale one.
unauthorized (401)A password is set and the session cookie is missing or expired. Log in again.
run routes are disabled — start the dashboard with \locac web --enable-runs`` (404)Launching runs from the browser is opt-in.

Details in Dashboard & evaluation.

Evaluation

error: no labeled fixtures under <dir>

error: no labeled fixtures under eval/fixtures/mixed (need a labels.json, or subdirs with one)

--fixtures must point at a directory holding a labels.json, or at a parent whose immediate subdirectories do. Fixtures are not shipped in the binary: the corpus is yours.

no-significant-difference on an obvious improvement

The verdict is decided by the bootstrap interval, not by which mean is larger. With few trials the interval is wide enough to include zero, which is the honest answer. Raise --trials before believing a small ΔS.

Interrupting a run

Ctrl+C once:

^C — finishing the current step, then stopping (Ctrl+C again to force)

The current tool call completes so the transcript stays consistent and the session is resumable. A second Ctrl+C stops immediately.

Exit codes

CI reads this number and nothing else, so an audit that stopped early is distinguishable from one that finished and found nothing.

CodeMeaning
0The run completed
1A real failure: a startup error, or the run ended in error
2Incomplete: capped by --max-iterations, --max-tool-calls, --max-tokens or --max-wall-clock-ms. Raise the cap and resume
130Interrupted (the shell's SIGINT convention)

Still stuck

Reproduce with the sandbox verdict visible and the run's own numbers in front of you:

locac selftest
locac config show      # ⚠ prints the effective config, apiKey included: redact before sharing
locac sessions

The transcript of a failed run is in the session database and survives the failure. locac resume picks up from it rather than restarting, which is usually faster than reproducing from scratch.