Troubleshooting

Symptom, cause, and fix for the most common orch friction points: the reaper, stale locks, PATH, second Chair, permission timeouts, silent hooks, and usage showing zero.

Grep this page by the error string you're seeing — each row is a self-contained symptom/cause/fix triplet.

The reaper reclaimed a session I thought was still running#

  • Symptom: locks, a running task, or a worktree from a session disappeared while you weren't watching.
  • Cause: the daemon reaps dead sessions on a clock (daemon.reap_interval_sec, default 60s). Once a killed/crashed agent's seat looks abandoned, the reaper frees what it held: its shared_locks rows, its running task row, and — for an isolated checkout — its worktree.
  • Fix: expected cleanup, not a bug. To stop it entirely (not recommended), set daemon.reap_interval_sec: 0.

A shared-path lock won't budge, or orch lock acquire fails#

  • Symptom: orch lock acquire <path> --holder <id> fails, or a stale lock blocks a guard check.
  • Cause: locks carry a TTL (--ttl-min, default 15 minutes) — a session that died before releasing leaves the lock held until it expires.
  • Fix: orch lock status <path> (or no path, for the full list) shows expires_at; once expired, any holder can re-acquire it. orch msg stale --older-min 15 finds stale unread alerts more broadly.

orch: command not found after install#

  • Symptom: orch isn't recognized in a new shell right after install.
  • Cause: orch setup updates the user PATH, not the current process's PATH — an already-open shell doesn't see the change.
  • Fix: open a new terminal. If it's still missing, run orch setup --prune-path --dry-run to see what orch believes is on PATH, then orch setup --prune-path to reconcile.

"project already has Chair session … — one Chair per project"#

  • Symptom: starting a second interactive Chair on the same project is refused with that exact message.
  • Cause: by design, a project runs one interactive Chair at a time (ChairOnly seat claim) — two Chairs racing to dispatch workers on the same project would double-claim work.
  • Fix: join the existing Chair session, or dispatch with --force-chair if it's actually dead and the reaper hasn't caught up. Workers never hit this — spawn them with orch task run.

A worker exits 126 or 124#

  • Symptom: a dispatched worker's .orch-agent.log ends with exit 126 or 124 and no useful diff.
  • Cause: 126 = orch detected a headless permission/write denial (the CLI tried to prompt interactively and couldn't). 124 = it hit agents.timeout_sec (wall-clock cap) or agents.idle_timeout_sec (no stdout/stderr for that long).
  • Fix: for 126, make the preset's headless command allow writes without an interactive prompt — see configure-agents.md. For 124, raise agents.timeout_sec/--timeout, or raise/disable agents.idle_timeout_sec if the agent is just slow.

A context hook seems to do nothing#

  • Symptom: context.hooks.post_tool/pre_compact is true in orch.yaml, but tool output never shrinks and BOARD.md never condenses.
  • Cause: orch hook post-tool/pre-compact resolve orch.yaml the same way every command does — outside a registered workshop (no resolvable orch.yaml) the hook silently returns and does nothing, by design (a context hook must never fail loudly and break the agent it's helping).
  • Fix: confirm orch home resolves a workspace from where the hook runs, and that orch guard wire --claude (or the OpenCode plugin wire) actually installed it — the orch.yaml flag alone doesn't wire it in.

orch usage shows zero right after a session#

  • Symptom: a plan-billed seat (e.g. Claude Code on its own login) just ran, but orch usage shows no tokens for it.
  • Cause: there's no billing API for a plan login — usage for these seats comes from scanning the harness's own transcript files under ~/.claude/projects/<slug>/*.jsonl, which can lag the live session.
  • Fix: re-run orch usage after the transcript is written — it scans transcripts on every invocation, so a second run is enough.