---
audience: agent
humans: https://capxule.com
page: errors
status: live
version: 2026-10-11
canonical: https://capxule.ai/errors
mcp: https://capxule.ai/mcp
schema: https://capxule.ai/schemas/error.json
---
# capxule.ai errors
> This site is written for AI agents. If you are a human, go to https://capxule.com

Token cost: this page sends x-markdown-tokens. Cache 3600 s. Schema: https://capxule.ai/schemas/error.json.

## 1. The envelope
Every tool error is one shape: `code`, `for_human` (say it), `for_agent` (do it), `next` (a tool call or a URL, never advice), `retryable`, `retry_after_ms`, `doc`, and on `capsule_not_found` `alternatives` (at most three published cards). On MCP it rides structuredContent and content[0].text; a tool error is HTTP 200 with isError: true. Transport failures (401, 403, 429) precede JSON-RPC and never arrive as tool errors.

## 2. Errors
| code | kind | retryable | next | for_agent |
|---|---|---|---|---|
| `session_expired` | error | no | open_journey({capsule_id, resume?}) | Call open_journey with the same capsule_id; a bound principal resumes automatically, an open principal needs the resume code. |
| `session_required` | error | no | open_journey (with _meta.subject on /mcp/open, or Bearer oat_ on /mcp) | Call open_journey first (with _meta.subject on the open mount, or a Bearer token carrying the journey scope) and pass the returned session on every later call. |
| `capsule_not_found` | error | no | pick one of `alternatives`, or find_capsule({query}) | The id or slug does not resolve to a published journey. Pick one of `alternatives` or call find_capsule with the user's words. |
| `turn_conflict` | error | no | turn with a fresh turn_id | This turn_id was already used with a different action. Send the new action under a fresh turn_id; never reuse ids across distinct actions. |
| `rate_limited` | error | yes | wait retry_after_ms, repeat the same call (the window may be a minute, a day, or the new-session floor) | An allowance for this identity is used up for the current window. Wait retry_after_ms, then retry the same call. |
| `preparing` | error | yes | wait retry_after_ms, turn with the SAME turn_id | The reply is still generating server-side and will be stored under this turn_id. Wait retry_after_ms and call turn again with the SAME turn_id; the retry returns the stored beat and spends nothing. |
| `locale_unavailable` | error | no | proceed in `served`; tell the human | Requested locale is not served for this journey; `served` names the locale actually used. Proceed, and tell the human. |
| `not_available` | error | no | pick from the last beat's options; with reason bind_required: account_bind first; machine_cannot_bind: machines never bind (day_pass is theirs); machine_only: a human's plan pays, not day_pass | The action is not available on this journey or in its current mode (practice on a non-prep journey, exit outside practice, resume before arrival). Use one of the options on the last beat instead. |
| `option_invalid` | error | no | pick from the latest beat's options, or say{text} | The option id does not belong to the LAST beat of this session (ids are per beat). Pick from the latest beat's options, or send the human's words with action kind `say`. |
| `invalid_arguments` | error | no | call the same tool with arguments that validate against its inputSchema (a stale consent.text_version lands here too) | The arguments did not match the tool's inputSchema; `issues` lists each path. Fix them and call the same tool again. No turn was spent. |
| `moderation` | error | no | rephrase or move on; no turn was spent | The message did not pass the content screen. Rephrase or move on; no turn was spent. |
| `unavailable` | error | yes | wait retry_after_ms; then find_capsule for another journey | A server-side dependency failed. Retry after retry_after_ms; if it persists, offer find_capsule for a different journey. |
| `challenge_expired` | error | no | account_bind again with the same method and target (a fresh challenge) | The challenge is past its TTL or its attempts. Call account_bind again with the same method and target to get a new challenge; the old id is dead. |
| `code_invalid` | error | no | ask the human to re-read the code; account_verify with the same challenge (`attempts_left` remain) | The code did not verify; `attempts_left` says how many tries remain before the challenge dies. Ask the human to re-read the code and call account_verify with the same challenge. |
| `email_rejected` | error | no | ask for a different address; account_bind again (other methods available right now are listed in alternatives) | The address failed the quality gate (malformed, disposable domain, no MX, or too many disowned accounts). Ask for a different address and call account_bind again; any other method available right now is listed in alternatives. |
| `phone_rejected` | error | no | offer email_code (the default); account_bind again | The number is not a reachable mobile in E.164, is on the denylist, or the SMS ceiling is hit. Offer email_code (the default) and call account_bind again. |
| `delegation_limit` | error | no | the human removes an assistant on the web account page (`next.url`); no agent action frees a slot | The user holds DELEGATION_CEILING active delegations. The human removes one on the web account page (`next.url`); no agent action can free a slot. |
| `host_policy` | error | no | offer the public page in `next.url` only; never a plan name, price or checkout link | Brokering a payment link is not permitted on this platform. Offer the public page in `next.url` only; never a plan name, price or checkout link. |
| `authorization_pending` | error | yes | poll account_verify again after `interval` seconds with the same device challenge | RFC 8628: the human has not yet approved the device code. Poll again after `interval` seconds with the same device_code. |
| `slow_down` | error | yes | add 5 seconds to the polling interval; poll again with the same device challenge | RFC 8628: you polled faster than the interval. Add 5 seconds to your polling interval and poll again with the same device_code. |
| `pass_expired` | error | no | day_pass({}) to settle a new pass (or day_pass({code}) with a web-sold code); premium journeys stay walled until then | The machine principal has no live day pass (expired, forfeited, or its turn ceiling reached). Call day_pass to settle a new one; premium journeys stay walled until then. |
| `payment_pending` | error | yes | wait retry_after_ms; day_pass again with the same receipt | The rail has not settled the receipt. Wait retry_after_ms and call day_pass again with the same receipt. |

## 3. Walls (inside a beat, never errors)
| code | kind | retryable | next | for_agent |
|---|---|---|---|---|
| `trial_exhausted` | wall | no | wall.next: bind_account (account_bind, then account_verify); alt: inform_url (the public page) | The open allowance for this journey is spent. `wall.next` is bind_account (then account_bind: ask for an email, read back the masked address, call account_bind, then account_verify with the code the human reads you); `wall.next.alt` is the journey's public page for a human who prefers the web. Never a plan name or price. |
| `premium_required` | wall | no | wall.next: inform_url (the journey's public page on capxule.com); alt (brokering hosts only): call plan_upgrade; machine principals: pay (day_pass) | The principal's plan does not include this journey. Offer `wall.next.url` (the public page) and nothing more: never a plan name, never a price. Where the client's platform record permits brokering, `wall.next.alt` names plan_upgrade: offer to send a secure payment page to a channel the human names in their own words. A machine principal gets `next: {kind: pay, then: day_pass}` and no for_human. |
| `budget_exhausted` | wall | no | wall.next: inform_url (the journey on app.capxule.com) | The lifetime per-journey turn budget (three turns per stop) is spent for this principal. Offer `wall.next.url`; the budget never resets. |
| `tokens_exhausted` | wall | no | wall.next: inform_url (the journey's public page on capxule.com) | The bound account's token allowance is exhausted (web plan limits). Offer `wall.next.url` (the journey's public page); do not retry turns. |
| `stepped_down` | wall | no | wall.next: inform_url (the human's account page) | This delegation is stepped down (a first strike of the usage detector): the open allowance applied and is spent. The human already has an account: NEVER offer account_bind; offer `wall.next.url` (their account page) and stop. |

## 4. Transport
| code | kind | retryable | next | for_agent |
|---|---|---|---|---|
| `http_401` | transport | no | OAuth at /.well-known/oauth-protected-resource, or /mcp/open | No valid Bearer on /mcp. Follow WWW-Authenticate: resource_metadata to the OAuth metadata and connect; or use /mcp/open with _meta.subject. |
| `http_402` | transport | yes | settle on the rail; day_pass({receipt, rail}) | Machine principals only: day_pass answered with the rail's payment challenge (x402 or Stripe MPP) in the body and the Payment-Required header. Settle on the rail, then call day_pass again with the receipt. No human relays this. |
| `http_429` | transport | yes | wait Retry-After, repeat the same call | Rate tier exceeded for this identity. Wait Retry-After seconds (also X-RateLimit-Reset), then repeat the same call. |

## 5. Relay to your human
Say `for_human` as given. An off-topic question is not an error: the beat redirects in the journey's own voice. Lines by moment and locale: https://capxule.ai/relay.
generated_at: 2026-10-14T10:11:49.291Z
