Skip to content

Troubleshooting

barkley-clawd edited this page Aug 8, 2026 · 3 revisions

Troubleshooting

Symptom first, cause second, fix third.

Symptom first, cause second, fix third. The daemon's log (<state_dir>/processor.log) is the authoritative record of what happened; caduceus status --json is the authoritative record of what the daemon thinks is happening now. Start with those two and you'll answer most questions yourself.

Install problems

hermes caduceus setup fails with "rustc not found"

Rust isn't on the PATH Hermes's subprocess sees. Install rustup, make sure ~/.cargo/bin is on PATH for the user running the plugin, rerun setup.

setup fails with "rustc does not meet the minimum version"

The installed toolchain is older than the pinned Rust version. rustup update, rerun setup.

setup fails with "Cargo.lock would need updates"

The daemon builds with --locked, so setup refuses to modify the lockfile — on purpose. Run cargo update locally, commit the lockfile change, rerun setup.

Standalone: caduceus run exits 1 with "worker_command is required for standalone"

You skipped the one mandatory config field. Set worker_command under the caduceus: section (see Configuration).

Runtime problems

caduceus status reports state_corrupt: true

state.json or state_meta.json failed validation. Do not edit the file in place. Follow State Recovery.

status reports last_http_status: 401

The GitHub token is invalid, expired, or missing permissions. Check the log for the exact error, then confirm the token exists and carries Metadata: read, Contents: read/write, Issues: read/write, Pull requests: read/write.

status reports next_allowed_poll_at in the future

GitHub rate-limited the daemon. It respects X-RateLimit-Reset and won't poll until then. This is correct behaviour — don't bypass it, and don't file a bug about it.

Cron fires but caduceus run exits 1 with "another tick holds daemon.lock"

That message is normally exit 0 (a concurrent tick — fine). Exit 1 means the lock acquisition itself failed: filesystem permissions, weird ownership, that sort of thing. Check <state_dir> is mode 0700 and owned by the user cron runs as.

A worker hangs and never finishes

The supervisor enforces worker_timeout_seconds with SIGTERM → SIGKILL and a grace window. Check <state_dir>/runs/<run_id>.log for the transcript and the daemon log for the timeout line. If it times out consistently, either the harness is genuinely slow for that issue (raise the timeout) or it's hanging itself (run the bridge manually in the worktree and watch).

An issue never gets claimed

Claiming is gated by cadence (poll_interval_seconds), eligibility (next_attempt_at), and phase. The useful status --json fields: next_head (oldest queued issue), next_head_earliest_eligibility (when it's claimable), and the phases.* counts. If phases.queued is non-zero but next_head is null, the queue is malformed — file a bug with the JSON.

An issue claims repeatedly and fails with the same error

That's the retry budget doing its job — after max_retries_per_issue worker failures the issue goes Failed. Read the transcript and understand the failure before resetting anything. caduceus queue reset owner/repo#number --dry-run shows what a reset would do without doing it.

caduceus queue reset fails with "entry is Failed"

That's... the point. Reset exists to move terminal entries back to Queued. It works on Failed entries — the error you're seeing is the daemon refusing to reset an entry that's still actively claimed or not terminal. Check phases.failed and the issue's last_error.

The worker

Bridge exits 2 with "missing required env var"

The daemon didn't pass one of the CADUCEUS_* vars it should. Check status for daemon-side errors and the log for env-related lines. If the variable genuinely isn't arriving, that's a bug — file it with the status JSON.

Bridge exits 137 (killed by signal 9)

The hard timeout fired. Raise worker_timeout_seconds or fix the bridge to exit on its own.

worker-result.json is empty

The harness wrote zero bytes. The contract requires ≥ 1 byte and a valid schema; have the bridge validate the file before exiting 0.

The cron

Cron fires but nothing happens

Check <state_dir>/processor.log. If the daemon exits 0 with no log entries, the wrapper script is invoking the wrong binary or the wrong args — recheck what hermes caduceus cron-install generated.

Cron never fires

The Hermes gateway is down, or your managed cron provider is inactive. Caduceus doesn't own cron delivery; the gateway does.

I want a different cadence than every 2 minutes

poll_interval_seconds is the minimum cadence — cron can fire faster and the daemon gates. To actually slow it down, edit the cron job's interval. There's no Hermes-side knob for this without re-running cron-install against a different interval.

The public-voice rule

My comment got rejected for "caduceus" and my issue doesn't mention it

The match is a case-insensitive substring — caduceus in any case, anywhere in the text, trips it. Common culprits: the bridge template wrote the daemon's name into the summary, the harness echoed a prompt file that used the name, or the issue body contained it (the daemon only filters outbound text). Fix the bridge or override the list; don't fight the rule.

Getting help

Before filing an issue, gather: caduceus status --json output; the <state_dir>/processor.log tail; the affected issue's last_error; the bridge transcript at <state_dir>/runs/<run_id>.log (read-only — don't delete it). File at the project's GitHub issues. No secrets.

Caduceus docs

Clone this wiki locally