Skip to main content
Both developer surfaces return a stable, machine-readable error_code so an agent can branch on the failure instead of parsing prose. The CLI puts it in the --json error envelope; the MCP prefixes the tool-failure message with [error_code]. The same vocabulary backs both, mapped from the backend’s HTTP status (or from a structured body the backend sends). This page is the index of those codes. For how the CLI emits the envelope and exit codes, see global flags. For how the MCP renders failures, see tool conventions.

CLI error envelope

In --json mode every failure prints a JSON object to stderr and the process exits non-zero.
{
  "error": "Workspace not found",
  "error_code": "not_found",
  "retryable": false,
  "suggestions": ["Run a list command to see available resources"]
}
error
string
The human-readable message. Server-side entity names are remapped to CLI vocabulary (Product becomes Workspace, Profile becomes Person).
error_code
string
The stable code from the table below. Branch on this, not on the message text.
retryable
boolean
true only for transient failures (timeout, rate limit, 5xx, network). A retryable code is safe to retry after a short wait; a non-retryable one needs a fix first.
suggestions
string[]
Zero or more actionable next steps. Present on most codes.
error_kind
string
Optional. A finer sub-type on some client-thrown failures (see error_kind).
example
string
Optional. A copy-pasteable invocation that fixes the call (for example, the same command with --yes).
The exit code is derived from the same failure. See the exit-code table: 0 success, 1 general (including billing walls), 2 usage or validation, 3 auth, 4 not found, 5 transient.

MCP error format

A failing MCP tool raises a tool error whose message is prefixed with the bracketed code, so the calling model can read both at once:
[not_found] Study not found
When the backend sends a structured envelope (media pre-flight, rehost), the message also carries a Suggestions: ... line and an [envelope] {json} suffix the agent can parse for the modality-specific error_kind, suggestions, and any extra fields. See tool conventions for the shared id and validation rules that raise [validation_error] before any backend call.

Error codes

The core vocabulary, mapped from the backend HTTP status. The CLI and MCP map identically except for HTTP 403, noted below.
error_codeHTTPRetryableMeaning
auth_failed401, 403noToken missing, invalid, or expired. Re-authenticate. On the CLI a bare 403 maps to forbidden; see below.
forbidden403noCLI only. The account lacks access to the resource. (The MCP maps 403 to auth_failed.)
insufficient_credits402noThe simulation credit pool is empty. Not a bug and not an auth failure.
not_found404noThe workspace, study, ask, person, or other entity does not exist.
timeout408yesThe request did not complete in time. The write may still have landed (see below).
validation_error422noThe request body or arguments failed validation. The envelope lists the offending fields.
rate_limited429yesToo many requests. Wait, then retry.
server_error5xxyesA backend fault. Safe to retry; worth reporting if it persists.
client_errorother 4xxnoMCP only. An unmapped 4xx response.
request_failedothernoCLI fallback for an unmapped status.
network_errornoneyesThe API host could not be reached (DNS, connection refused, reset).
The CLI and MCP map HTTP 403 differently. The CLI distinguishes a true permission failure (forbidden) from a token problem (auth_failed is 401 only); the MCP folds both into auth_failed. Branch on the code your surface returns, not on the status.

Body-supplied codes

These codes are not in the status map. The backend sends them in the response body and both surfaces prefer them over the status-derived code.
error_codeHTTPRetryableMeaning
usage_limit_reached403noA plan entity cap was hit (for example, the free tier’s one-workspace limit). Arrives as 403 but is a billing wall, not an auth failure, so it exits 1, not 3. Free a slot or upgrade.
unknown_errornonenoCLI fallback for a thrown value that is not an Error. Rare.
usage_limit_reached and insufficient_credits are distinct: the first means too many stored studies, people, or workspaces; the second means the per-run credit pool ran out.
Do not treat a billing wall as an auth failure. usage_limit_reached and insufficient_credits both arrive on a 403 or 402 but exit 1 on the CLI. Re-authenticating loops forever. Free a slot, buy credits, or upgrade instead.

Structured (modality) error kinds

Media pre-flight and rehost failures replace the generic code with a specific error_kind so the agent sees the cause directly. Examples returned today:
error_kindMeaning
no_audio_trackA video study got a silent clip. Use a video with an audio track, or switch the study to the image modality if the source is really a still.
media_download_failedThe source URL could not be fetched or rehosted.
The full envelope (error_kind, error_message, suggestions, and modality-specific fields such as source_url) is preserved verbatim so the agent can branch programmatically.

error_kind sub-types

Some client-side failures carry an error_kind that refines a generic code. These come from the CLI and MCP themselves, not the backend.
error_kindWhereMeaning
ConfirmationRequiredCLIA billable or destructive command refused in non-interactive context. Pass --yes (or set ISH_ASSUME_YES=1). Exits 2. The example field shows the fixed command.
TunnelInactiveCLIA chat endpoint test ran with no live tunnel. Transient; exits 5.
BotAuthErrorCLIThe chatbot rejected the configured credentials. Transient; exits 5.
BotShapeErrorCLIThe chatbot response did not match the expected shape. Exits 2.
stale_workerbothA simulation worker died; the backend reaper flips the run to failed after about 15 min. Stop polling.
participant_subset_invalidbothAn ask or run targeted a participant subset that does not apply.

Timeout and wait codes

error_codeRetryableMeaning
timeoutyesA transport timeout (default 15 s; deletes 60 s). The response never arrived, but the write often landed server-side.
wait_timeoutyesA --wait timer expired while a job was still running. The job keeps going; re-poll the same id, do not re-enqueue.
On a [timeout] for a write (create, iterate, run, delete), the backend write may have succeeded even though the response never reached the client. A naive retry creates duplicate studies, iterations, or dispatches. Verify first. The MCP timeout message names the exact verify call to run (for example, study_get(study_id=..., lean=True)), and the CLI delete timeout points you at the matching get before retrying.

Recovering by code

CodeWhat to do
auth_failed, forbiddenRun ish login, or reconnect the MCP. Confirm the account has access.
not_foundRun a list command. A stale active workspace or study saved in config can 404; run ish status, then ish workspace use --clear.
insufficient_creditsBuy credits or wait for the monthly refresh on a paid plan. See run vs ask for what draws credits.
usage_limit_reachedDelete an unused study, person, or workspace, or upgrade the plan.
validation_errorRead the listed fields. Add --help to the command, or check the tool reference.
rate_limited, server_error, timeout, network_errorWait briefly and retry. For a write timeout, verify the write landed first.
wait_timeoutRe-poll the same job id. Do not re-run.
When a failure looks like a genuine bug (an unexpected 5xx, a fault you cannot act on), report it with ish feedback and add --health for setup or simulation issues. User-actionable failures (auth, not found, validation, billing) are never flagged as bugs.