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.
The human-readable message. Server-side entity names are remapped to CLI vocabulary
(
Product becomes Workspace, Profile becomes Person).The stable code from the table below. Branch on this, not on the message text.
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.Zero or more actionable next steps. Present on most codes.
Optional. A finer sub-type on some client-thrown failures (see error_kind).
Optional. A copy-pasteable invocation that fixes the call (for example, the same command with
--yes).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: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_code | HTTP | Retryable | Meaning |
|---|---|---|---|
auth_failed | 401, 403 | no | Token missing, invalid, or expired. Re-authenticate. On the CLI a bare 403 maps to forbidden; see below. |
forbidden | 403 | no | CLI only. The account lacks access to the resource. (The MCP maps 403 to auth_failed.) |
insufficient_credits | 402 | no | The simulation credit pool is empty. Not a bug and not an auth failure. |
not_found | 404 | no | The workspace, study, ask, person, or other entity does not exist. |
timeout | 408 | yes | The request did not complete in time. The write may still have landed (see below). |
validation_error | 422 | no | The request body or arguments failed validation. The envelope lists the offending fields. |
rate_limited | 429 | yes | Too many requests. Wait, then retry. |
server_error | 5xx | yes | A backend fault. Safe to retry; worth reporting if it persists. |
client_error | other 4xx | no | MCP only. An unmapped 4xx response. |
request_failed | other | no | CLI fallback for an unmapped status. |
network_error | none | yes | The 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_code | HTTP | Retryable | Meaning |
|---|---|---|---|
usage_limit_reached | 403 | no | A 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_error | none | no | CLI 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.
Structured (modality) error kinds
Media pre-flight and rehost failures replace the generic code with a specificerror_kind so the
agent sees the cause directly. Examples returned today:
error_kind | Meaning |
|---|---|
no_audio_track | A 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_failed | The source URL could not be fetched or rehosted. |
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 anerror_kind that refines a generic code. These come from the
CLI and MCP themselves, not the backend.
error_kind | Where | Meaning |
|---|---|---|
ConfirmationRequired | CLI | A 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. |
TunnelInactive | CLI | A chat endpoint test ran with no live tunnel. Transient; exits 5. |
BotAuthError | CLI | The chatbot rejected the configured credentials. Transient; exits 5. |
BotShapeError | CLI | The chatbot response did not match the expected shape. Exits 2. |
stale_worker | both | A simulation worker died; the backend reaper flips the run to failed after about 15 min. Stop polling. |
participant_subset_invalid | both | An ask or run targeted a participant subset that does not apply. |
Timeout and wait codes
error_code | Retryable | Meaning |
|---|---|---|
timeout | yes | A transport timeout (default 15 s; deletes 60 s). The response never arrived, but the write often landed server-side. |
wait_timeout | yes | A --wait timer expired while a job was still running. The job keeps going; re-poll the same id, do not re-enqueue. |
Recovering by code
| Code | What to do |
|---|---|
auth_failed, forbidden | Run ish login, or reconnect the MCP. Confirm the account has access. |
not_found | Run a list command. A stale active workspace or study saved in config can 404; run ish status, then ish workspace use --clear. |
insufficient_credits | Buy credits or wait for the monthly refresh on a paid plan. See run vs ask for what draws credits. |
usage_limit_reached | Delete an unused study, person, or workspace, or upgrade the plan. |
validation_error | Read the listed fields. Add --help to the command, or check the tool reference. |
rate_limited, server_error, timeout, network_error | Wait briefly and retry. For a write timeout, verify the write landed first. |
wait_timeout | Re-poll the same job id. Do not re-run. |
ish feedback and add --health for setup or simulation
issues. User-actionable failures (auth, not found, validation, billing) are never flagged as bugs.