-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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).
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.
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.
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.
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.
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
- Home — what it is, and the one rule
- Installation — get it running
- Configuration — the settings that matter
- The-Bridge — make the worker yours
- State-Recovery — when things go wrong
- Troubleshooting — fix it
- FAQ — quick answers