Troubleshooting
When a run fails, crab’d updates its tracking comment with what happened, what to change, and a link back here — instead of a raw stack trace. This page expands on each failure it can post.
Every failure comment names the specific config knob to adjust. The knobs live under
limits and rate_limit
in your .crabd.yml (or the equivalent in
crabd.config.ts).
Run hit the turn limit
Section titled “Run hit the turn limit”crab’d stopped … — it reached the tool-call limit before finishing.
Every run has a hard ceiling on tool-calling turns (limits.max_turns, default 40). When a
run reaches it, crab’d is stopped mid-task. This is a safety valve against runaway loops and
unbounded CI cost — it is not injected into the prompt, so the model isn’t biased into stopping
early.
Before it stops, crab’d reserves a few turns to ask the model for a best-effort final answer — so the comment usually carries a partial result (what it found, what’s still open) rather than nothing. When it does, the comment is marked as partial.
Common causes:
- The task was too broad for one run — e.g. “review this” on a PR touching dozens of files, or an open-ended “look into X”.
- crab’d chased something it couldn’t finish — most often a file or another repository it has no access to (its token is scoped to the current repo), then looped retrying.
What to change:
-
Narrow the request. Point crab’d at the specific files or the specific change you want feedback on, or split a large PR into smaller ones.
-
Raise the ceiling only if the task genuinely needs more steps:
limits:max_turns: 80 # default 40
Raising max_turns trades CI minutes (and tokens) for headroom — prefer narrowing the task first.
Run timed out
Section titled “Run timed out”crab’d ran out of time … — the run exceeded its time limit.
A wall-clock limit (limits.timeout_minutes) was set and the run exceeded it. Unlike the turn
limit, this is off by default — you only see it if you configured it.
What to change:
limits: timeout_minutes: 20 # raise, or remove to disableIf runs routinely approach the limit, also consider narrowing the request (see above) or a faster model for the mode.
Rate limited
Section titled “Rate limited”crab’d … every model was rate-limited …
The provider rate-limited or overloaded crab’d, and every model in the fallback chain was exhausted (or the wait budget ran out). This has its own tuning surface — backoff, an ordered fallback-model chain, a wait budget, and per-mode soft/fail behavior. See Rate limiting & fallback models.
Configuration is invalid
Section titled “Configuration is invalid”crab’d couldn’t start … — its configuration is invalid.
crab’d couldn’t load or validate your config. The details block names the offending field. Check it
against the .crabd.yml reference or
crabd.config.ts reference, and see
Config layering & governance if a value isn’t taking effect (a higher layer may
override or forbid it).
Cross-repo reads aren’t working
Section titled “Cross-repo reads aren’t working”the agent can’t read another repository you granted with
repos.read
Most often the token can’t reach it. repos.read needs a cross-repo-capable token: your own App
(CRABD_APP_*, installed on those repos) or a scoped PAT. Under the default token broker — which
vends single-repo tokens by design — repos.read is ignored (the run logs this). Check the run logs,
and see Cross-repo access & private registries.
Private registry install fails
Section titled “Private registry install fails”
pnpm install/npm installcan’t authenticate
Confirm the secret is mapped to an env var on the crab’d step (env: { NPM_TOKEN: ${{ secrets.… }} }), that the same name is what the sandbox.npmrc entry’s token_env references (or is listed
in sandbox.env for a non-registry secret), and that the registry URL/scope match your dependency. A
name mismatch between the step’s env, token_env, and the secret is the most common cause. See
Cross-repo access & private registries.
crab’d logs a warning when it can’t resolve a registry token —
sandbox.npmrc: token env "NPM_TOKEN" is not set … — and tells the agent that registry is
unauthenticated so it reviews from source instead of thrashing on install retries (a missing token
otherwise burns a whole run’s tool budget on 401/403s). If you see that warning, the token never
reached the step. Note the forge-token fallback (omitting token_env for same-org GitHub Packages)
needs your own GitHub App with packages: read — it does not work under the hosted broker; use an
explicit token_env there.
crab’d won’t commit
Section titled “crab’d won’t commit”the reply ends with
I did not commit anything…, or a commit fails withResource not accessible by integration
Three reasons, in order of likelihood:
- The mention didn’t ask for a change.
mentionmode commits only when the comment asks for one. A bare/crabd, or a question, gets an answer even if crab’d noticed a fix worth making. Ask for the change explicitly. - Writes are off. Either
permissions.write: false, ormodes.implement.enabled: false, which turns writes off everywhere unless you setpermissions.write: true. Seepermissions. - The token can’t write. Your GitHub App installation grants
contents: read. crab’d now detects this at startup, warns, and runs read-only instead of failing at the commit, and the run log carries the warning. Grant the App Contents: Read and write, then accept the permission request on the installation (an org owner has to approve it; raising the App’s permissions alone does nothing until the installation accepts). Older versions surfaced this only as a 403 fromPOST /repos/…/git/blobsat the very end of a run.
Unexpected error
Section titled “Unexpected error”crab’d hit an error …
A failure that doesn’t fall into the categories above. The comment includes a collapsed Error details block and a link to the run logs — start there. If it looks like a bug in crab’d, please open an issue.
Nothing happened at all
Section titled “Nothing happened at all”No comment, no 👀 reaction, no failure message. crab’d posts a comment for every failure it can attribute, so silence means it never got far enough to have anything to say. In order of likelihood:
- The job never ran. Check the run in your forge’s Actions tab. A job showing
skippedmeans itsif:was false, not that crab’d declined. Note that in a Forgejo reusable workflow the parent job still reports success when the inner job skips, so the run looks green. See thegithub.event_namecaveat. - The event isn’t one crab’d handles. The logs end with
event "…" is not handled. Skipping.crab’d acts onpull_request,issue_comment,pull_request_review_comment, andissuesonly. Apush, for example, is a deliberate no-op. - No trigger matched. A comment must contain the trigger phrase, and a
pull_requestonly auto-reviews onopened/reopened/ready_for_review, not on a push to the branch. Mention/crabd reviewto re-review. - The pull request is a draft. Draft PRs are never auto-reviewed. Mark the PR ready for review,
or mention
/crabd reviewin it. - The actor was filtered. Bots never trigger crab’d (to avoid comment loops), and the actor’s
association must be in
permissions.allowed_associations.
