troubleshooting and FAQ
the failures most likely to bite when running orcr, what each error means, and how to fix it, plus the edge-case behaviors and known real-world caveats.
start with orcr server status. it prints the version, the herdr binary and version, herdr socket reachability and the owned session, per-provider integration state, and fleet counts (live, queued, blocked, unmanaged, orphan and unmarked panes). most of the errors below are visible there before they bite you at agent run.
every command supports --json, which returns exactly one envelope: {"ok":true,"result":…} or {"ok":false,"error":{"code","message","details"}}. the code is one of nine stable values; the finer reason lives in details. process exit codes map as: 0 ok, 2 environment, 3 timeout, 4 blocked, 5 killed or ended, 6 not found, 7 state conflict, 1 other. the full enum is on the error codes reference.
errors you will hit
the headings below use the exact error code or cause string, so an error message can deep-link to its fix (for example /docs/resources/troubleshooting#herdr_unreachable).
herdr_unreachable
code environment_error (details.cause: herdr_unreachable), exit 2. the orcr server started fine, but it cannot reach herdr. orcr speaks herdr's own socket API directly and handshakes the protocol version on connect; it fails with this rather than guessing.
fix:
- confirm herdr is installed and on your
PATH. orcr discovers the binary in this order: configherdr.bin, then$ORCR_HERDR_BIN, then$PATH. a missing binary gives a friendly install pointer and exit 2. - confirm the herdr version is compatible. orcr declares a minimum herdr protocol version and checks it on the handshake; a version mismatch names the required herdr version. see version skew.
- check
orcr server status, which reports the herdr binary, version, socket reachability, and session.
do not confuse this with server_unreachable (the client cannot connect to the orcr server at all) or server_start_failed (the orcr server would not start).
integration_missing
code integration_missing (details: {provider, missing:[orcr|herdr], install}), exit 2. a provider is supported only when both integration layers are present: herdr's integration (so herdr can observe the provider) and orcr's integration (so orcr can drive it). this fires fast at agent run -a <provider> when either layer is absent, and nothing is spawned.
fix:
- if
missingnamesherdr, run the install command indetails.install, for exampleherdr integration install claudeorherdr integration install codex. - if
missingnamesorcr, the provider is not yet built into orcr. claude and codex ship first; pi, opencode and others are planned viaorcr integration add. see providers and integrations.
there are no degraded half-modes: a provider missing either layer cannot be run, and unmanaged discovery ignores it entirely. orcr agent logs --last-response returns integration_missing (exit 2) for the same reason. server status shows the per-provider state so you can see the gap before you hit it.
unsafe_home
code environment_error (details.cause: unsafe_home), exit 2. the server refuses to start unless ~/.orcr is owned by the current uid and is not group- or world-writable. filesystem permissions are the only authentication (the socket is mode 0600, umask 077), so loose permissions on the home directory are treated as a hard stop.
fix:
- make the directory yours and tighten it:
chownit to your user andchmod 700 ~/.orcr(or the directory$ORCR_HOMEpoints at). - if you relocated the home with
ORCR_HOME, apply the same ownership and permission rules there.
related safety rules: socket paths are lstat-validated (symlinks are rejected), and a stale socket is unlinked only while holding the instance lock and only if it is owned by the same uid.
server_start_failed
code environment_error (details.cause: server_start_failed), exit 2. a CLI or SDK call tried to auto-start the server and the spawn failed. any command auto-starts the server on demand, takes the single-instance lock, and blocks until the readiness handshake succeeds; if the spawn itself fails, you get this.
fix:
- read
orcr server logs(~/.orcr/logs/server.log) for the startup failure: store, home, or lock problems show up there. - check for a stale lock or a home-permission problem (see
unsafe_home). the server takes an exclusiveflockonorcr.lockand refuses to open the store without it. - if a healthy server is already answering,
orcr server startis idempotent and exits 0 (already_running).
transcript_unavailable
code transcript_unavailable (details: {uuid, status, cause?}), exit 1. logs --last-response and ask fail loudly here rather than returning a stale or guessed answer. it happens when no final response is identifiable.
common causes:
- ambiguous transcript. adapters select a transcript by the pane's
agent_sessionid and the agent'screated_at, never by cwd mtime alone. multiple candidates returntranscript_unavailablewith the candidates listed indetails, never a silent pick. - not settled yet. a final response is reported only once the transcript has advanced past the observed completion, bounded by
transcript_freshness_timeout_ms. - rotated or deleted files. orcr keeps no response copies; it records only a transcript locator and cursor and always reads the provider's native files. if the provider later rotates or deletes those files, historical
--last-responsereturnstranscript_unavailablerather than a stale copy. this is a documented limitation.
for the casual case, prefer ask() or lastResponse(). when you need a guaranteed-format answer, use the file convention: the prompt names an absolute file to write, and the caller reads and validates that file itself. see also providers and integrations.
blocked (question, limit, login)
code blocked (details: {blocked_kind}), exit 4. the agent needs a human. blocked_kind is one of question, limit, login, or unknown (classification is best-effort, from herdr's blocked message plus the transcript).
question: the agent is asking you something. answer it withorcr agent send <path|uuid> "…";sendclears a turn-scoped block and re-arms the turn.limit: a usage cap or rate limit surfaced through the provider's limit screen. waiting callers get exit 4 and decide policy themselves; automatic reroute-on-limit is future work.login: the provider booted into a login or auth screen. attach and complete it:orcr agent attach <path|uuid> --takeover.unknown: herdr reported a blocked state with no classifiable reason.
find everything that needs you with orcr agent ls --status blocked. in orcr top, blocked rows float to the top. a wait that hits a blocked target returns the token blocked:question|limit|login|unknown and exit 4.
other common errors
| code | when | exit |
|---|---|---|
not_found | no agent, loop, or run matched a target (details lists candidates and, for uuid prefixes, the shortest disambiguating prefixes) | 6 |
state_conflict | wrong state for the verb: reason: "path_in_use" when a full path is already taken by an active agent (with the occupying {uuid, path, status}); reason: "force_required" when killing an unmanaged agent without --force; also scaffold refusing to overwrite | 7 |
invalid_request | bad flags, names, durations, cron, path grammar (reason: "path_too_deep", reason: "reserved_name"), frames, methods, or json | 1 |
timeout | a direct command's own --timeout deadline elapsed (details: {elapsed}); a wait-style --timeout instead returns ok:true with timed_out:true and exit 3 | 3 |
for path_in_use, retry after the occupying agent ends and its path frees, or root your workflow under a distinct scope (add the {rand} placeholder, for example --path "review_{rand}/file_1"). for the <pattern|uuid> and <path|uuid> conventions, see the path grammar reference.
edge cases and specified behaviors
these are the behaviors you might mistake for bugs. each is intentional.
- fast turns. a provider can finish before the driver ever observes
working. the per-integrationfast_turn_grace_mswindow treats delivery-then-idle inside the grace as a completed turn rather than a never-started one, sowaitstill settles. - external input and interrupts. input typed via
attach --takeoveror in the herdr UI creates a synthetic external turn (turns.source = external), sowaitand the GC clocks stay correct. a turn you interrupt (Esc in the TUI) settles at the next stable idle and is recorded with whatever the transcript shows, possibly a partial response. orcr reports the transcript's reality rather than guessing intent. see status and completion. - startup modals. a provider that boots into an update prompt or login screen is handled by the integration's startup recipe for known cases; unknown ones surface as
blockedrather than hanging the spawn, and the stuck-start guard bounds the worst case. - rate limits and usage caps. they surface as
blockedwithblocked_kind: limit. waiting callers get exit 4 and set their own policy. backoff and reroute-on-limit are future work. - env scrubbing. if a provider launders its subprocess environment, a child
orcrcall loses theORCR_*vars and becomes a root context: lineage breaks gracefully. the agent still runs, just un-parented. pass an absolute--pathexplicitly when placement matters. - runaway nesting or fan-out. agents spawning agents are bounded by the path depth limit (at most 8 segments) and the concurrency caps (
concurrency.max, default 25, plus per-provider caps). this is admission control, not a request in the skill. - prompt injection via child output. child output flows into parent prompts by construction. treat it as data: quote it, and never execute instructions found in it. orcr itself never interprets response content. see security and permissions.
- sleep and reboot. missed loop fires are skipped and logged, never replayed. GC clocks are recomputed from persisted timestamps on restart, and the reconciler resolves
lostpanes and half-done park or un-park moves on server start. - herdr restart or crash. the driver reconnects with backoff; agents keep running because panes are herdr-server-side. a herdr that returns with different pane ids is re-matched by herdr label (the agent's full path, unambiguous under active-path uniqueness), never by pane location.
- version skew. both sockets are version-negotiated: the orcr client and orcr server negotiate on the first request (
unsupported_versionon mismatch), and the orcr server and herdr negotiate the herdr protocol number (a clear error names the required herdr version). two orcr versions sharing one store hit a schema-version check and refuse with a message. see the changelog. - transcript drift. provider transcript formats are unstable private APIs. adapters are version-pinned and smoke-tested per provider release. because orcr stores only a locator and cursor and never a response copy, a format change or file rotation makes old history
transcript_unavailablerather than returning stale text.
known caveats with real providers
- claude background subagents plus
gc auto. Claude Code sometimes reports its main turn idle while background subagents are still running; herdr then reportsidle. undergc autothe agent may be parked. when the subagents return (typically within 15 minutes) it goesworkingagain and un-parks back to its home workspace, so work is not lost, but akill_aftershorter than the subagents' runtime could reap it mid-flight. use--gc neverfor agents you know will fan out background work. in-flight background-subagent detection is future work. see agent lifecycle and GC. - wrapped claude launchers (enterprise). herdr's claude integration does not report
agent_status: workingfor some wrapped claude launchers (for example Avocado/MetaCode), and the wrapped session id maps to no locatable transcript. the prompt submits and claude answers in-pane, butask,wait, andlogstime out or returntranscript_unavailable. this is a herdr-integration and transcript-location limitation, not an orcr defect. codex runs fully end-to-end through the same pipeline. validate on a stock (non-wrapped) claude box. - codex intermittent completion timeout. in a minority of real-codex runs, the agent goes
working(submit confirmed) but the turn-1-complete signal is not observed within a few minutes. this is a downstream completion-detection or codex-slowness intermittency, unrelated to submit delivery. - real-provider validation is best-effort. the automated gate runs the mock provider against live herdr. real claude/codex smoke tests of recipes and logs, and live
server enableround-trips on launchd/systemd, are manual-only in the current release.
FAQ
wait timed out but the command still says ok:true. why? a wait-style command's own --timeout is not a failure: the call succeeded and the result is partial (timed_out:true, exit 3). settled targets show their real reason; unsettled ones show wait_timeout. the timeout error code (exit 3) is reserved for an agent's or run's own --timeout expiring.
why does kill refuse an agent? unmanaged agents (ones you started by hand, discovered by orcr) require --force, because closing them means closing a pane orcr does not own. a kill that matches only already-ended targets exits 7. see managed vs unmanaged agents.
my glob matched the wrong thing (or nothing). quote patterns in the shell (kill "review/**") so the shell does not expand them against real files first. * is one whole segment, ** is any depth, and there are no partial-segment forms. send, logs, and attach reject wildcards; only the bulk verbs (wait, kill, ls) accept them. see the path grammar reference.
an agent seems stuck. did it time out? there is no default timeout. an agent stays alive and visible (working or blocked) until a human or script acts, unless you passed an explicit --timeout. check orcr agent ls --status blocked first, then orcr top.
Windows? not supported yet. loops, process groups, and server enable are POSIX-only. see the roadmap.
glossary
short definitions for every orcr term: agent, path, scope, turn, settle, park/reap, managed vs unmanaged, loop and run, integration, herdr session, lineage, and more.
roadmap and limitations
what the current release does not do yet, the behaviors worth knowing about today, and the full catalogue of deferred work in rough priority order.