Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.blobhub.io/llms.txt

Use this file to discover all available pages before exploring further.

This page is the reference for the session_agent_harness job type: the error codes it can raise — in three classes beyond the generic process codes that fire before any section runs — and the v1 limitations specific to driving agents over a session.

Section validation

These fire during preflight, before the section is contacted. They exit the process with the code, the same way the generic process codes do.
CodeCauseRemediation
MISSING_SESSION_KEYSA section is missing one of org_id, blob_id, revision_id, session_id.Complete the section’s session block.
DUPLICATE_SECTION_TARGETTwo sections target the same session tuple.Remove one of the duplicates.

Section-level errors

One section fails to attach to its session; the failure is persisted in jobs/{job_id}/section.yaml.attachment.error and the section stops, while the worker keeps running all other sections.
CodeCauseRemediation
SESSION_OWNED_BY_DIFFERENT_USERThe worker session object’s metadata.user.user_id differs from ours.Manually free the session: delete_session_object(session_id, alias="worker").
SECTION_WORKER_OBJECT_MALFORMEDThe worker session object exists but its value.type is not "thread".Delete the malformed object and let the worker recreate it.
SESSION_DETACHED_EXTERNALLYThe worker session object was deleted while the section was attached.Re-attach by restarting the worker (or wait — the worker retries on next poll).
SESSION_NOT_FOUNDThe session 404’d or the API user lacks access.Check the (org_id, blob_id, revision_id, session_id) tuple and permissions.

Thread-level errors

A single thread transitions to failed, terminal until the user resets it (instance.state = "pending"). The error detail is persisted locally in jobs/.../threads/{alias}/thread.yaml (agent.error) — it is not written to the thread envelope. It surfaces to other clients as a thread_failed item in the worker activity thread.
CodeCauseRemediation
WORK_FOLDER_NOT_ABSOLUTEworkspace.work_folder is not an absolute path.Update the envelope to use an absolute path.
WORK_FOLDER_NOT_FOUNDThe path doesn’t exist on the worker host.Create the directory or fix the path.
WORK_FOLDER_NOT_A_DIRThe path exists but isn’t a directory.Point at an actual directory.
WORK_FOLDER_NOT_READABLEThe path exists but the worker process can’t access it.chmod / chown the directory so the worker user can read+execute it.
AGENT_TYPE_UNSUPPORTEDagent.type is not in claude_code / codex.Use a supported value.
PERMISSIONS_UNSUPPORTEDagent.permissions is not in autonomous / approval.Use a supported value (default is approval).
AGENT_EXECUTABLE_NOT_FOUNDAgent CLI (claude / codex) can’t be resolved on PATH.Install the agent; or override agents.<type>.executable in config.yaml.
AGENT_CRASHEDAgent process exited unexpectedly (exit code in error.message). A failed resume on restart also surfaces here.Inspect thread.log; reset the thread to pending to retry.
THREAD_POST_FAILEDPersistent 4xx posting items to the thread.Check session access; inspect thread.log for the rejected payload.
THREAD_ITEM_TOO_LARGEAn item exceeds the cap even after truncation (very rare).Inspect thread.log; reduce tool output size; reset the thread.

Transient errors

Logged and retried with exponential backoff up to polling.backoff_max_ms. They surface in the TUI warning ribbon and do not trigger any state-machine transition on their own (a long-running transient may eventually present as a thread-level THREAD_POST_FAILED after exhaustion).
CodeCause
API_TRANSIENT_ERROR5xx response from the BlobHub API.
API_RATE_LIMITED429 response.
API_NETWORK_ERRORConnection failed or timed out.
API_COMMAND_FAILEDGeneric 4xx-not-otherwise-classified.

Limitations

These trade-offs are specific to session_agent_harness. For generic worker limitations (no hot config reload, single-process / single-machine), see Reference.

Same-user posting collision

A human posting into a thread via the BlobHub web UI as the same user whose API key the worker uses is classified by the worker as “self” and ignored. The worker uses user_id as the only signal for filtering its own emissions out of the inbound stream; there is no per-post “posted by worker” flag in v1. Run the worker under a dedicated service-account user with its own API key so humans posting as themselves are seen as not-self and reach the agent.

No detach command

There is no blobhub-worker detach subcommand in v1. To free a session manually, delete the worker session object directly:
delete_session_object(session_id, alias="worker")
The running worker observes the deletion event and stops that section with SESSION_DETACHED_EXTERNALLY. Other sections continue.

Same-user worker races

Two worker installs sharing the same API key (same user_id) will race to overwrite each other’s worker marker silently — both will run and both will post. One worker install = one service-account user with one API key; don’t share credentials across machines.

No agent retry on failure

When an agent crashes or fails, the worker records the error in the local thread.yaml, transitions the thread to failed, and posts a thread_failed activity item. It does not auto-retry. Inspect thread.log / the local agent.error.message, then update the envelope to set instance.state = "pending"; the worker observes the change and re-runs the activation.

Unresolved interactive prompts don’t survive restart

If the worker is restarted while a pending_prompt is unanswered, the prompt is cancelled with pending_prompt_resolved (reason: worker_restart). The agent re-asks on resume if it still needs the input.

Multi-question prompt answering is best-effort

For ask_user_question prompts with multiple questions, the plain-text answer parser is best-effort (line-prefix 1) ..., 2) ... format). Unparseable replies fall back to each question receiving the raw text as a free-text answer. Answer one question at a time when the agent asks several at once.

No native UI for thread metadata editing

To put a thread into pending state for the worker to pick up, you currently update the thread envelope’s value.thread.metadata directly via upload_session_object (REST or SDK) — for example:
workspace:
  work_folder: /absolute/path/to/repo
agent:
  type: claude_code
instance:
  state: pending
There is no inline editor in blobhub-web for these fields in v1; a dedicated editor is a deferred fast-follow.

See also