> ## Documentation Index
> Fetch the complete documentation index at: https://agent37.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Stable, machine-readable error codes on both planes: branch on the code, show the message.

Every error uses a standard HTTP status code and returns a stable, machine-readable code in a JSON `error` field — an object with a `code` on both API catalogs, a flat string on transport failures between you and the gateway. Branch on the code, never on `message` or the HTTP status alone. There are two catalogs because there are two planes, plus a short list of transport errors.

<Info>
  Both planes take the same `sk_live_` key, as `Authorization: Bearer` on the hosting API and as `X-Agent37-Key` on instance URLs, but their error envelopes differ: the Agent API adds optional `param`, `hint`, and `response_id` fields. See [Core concepts](/agents-api/concepts) for the two planes.
</Info>

## Hosting API errors

Errors from `https://api.agent37.com/v1/*` always carry exactly `code` and `message`. There is no `param` or `hint` on this plane.

```json theme={null}
{
  "error": {
    "code": "insufficient_balance",
    "message": "This instance costs $0.0068 per hour, metered per minute; creating it requires at least one day of balance ($0.1624). Add balance to your workspace and try again."
  }
}
```

<ResponseField name="error.code" type="string">
  A stable, machine-readable identifier. Branch on this.
</ResponseField>

<ResponseField name="error.message" type="string">
  A human-readable description. Safe to show, but do not parse it.
</ResponseField>

### Hosting API codes

| Code                     | HTTP    | When                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `invalid_api_key`        | 401     | The `sk_live_` Bearer key is missing, malformed, or revoked, on any `/v1` path.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `invalid_request`        | 400     | A request field is invalid: bad JSON, an unsupported resource shape, a direct image ref where a template name belongs, a [template](/agents-api/templates) create with no `image_ref`, a not-publicly-pullable registry reference, starting a [template build](/agents-api/templates#build-an-image-in-the-cloud) whose context is missing or over 100 MB, a lifecycle action in the wrong state, or an invalid [`update`](/agents-api/instances#update) body (any field other than `template`, a bad or unpublished [version pin](/agents-api/templates#pin-a-template-version), or a template migration target that doesn't offer the instance's current shape). |
| `image_too_large`        | 400     | A [template](/agents-api/templates)'s staged image is over the 8 GB decimal cap (`8,000,000,000` bytes).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `forbidden`              | 403     | A write to a system template. System templates are read-only.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `not_found`              | 404     | No instance or template with that id or name in your workspace, or an unknown `/v1` path.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `insufficient_balance`   | 402     | The wallet holds less than a day of the instance's running rate at create, or is negative at `start` of a `past_due` instance.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `instance_limit_reached` | 409     | The workspace is at its instance limit: one instance on the free credit, 10 once you have topped up, 50 once top-ups total \$500. Email [vishnu@agent37.com](mailto:vishnu@agent37.com) to raise it further.                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `tier_limit`             | 403     | Create or resize asks for a shape larger than your plan includes, or a [custom domain](/agents-api/domains) is registered before your top-ups total \$500. Free workspaces (before your first top-up) run any template up to the 2 vCPU / 4 GB shape; a top-up unlocks the 4/8 and 8/16 shapes.                                                                                                                                                                                                                                                                                                                                                                    |
| `capacity_unavailable`   | 409     | `start` or `resize`: no host in the fleet can fit this instance, or the resize increase, right now.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `template_conflict`      | 409     | A template create or rename targets a name that already exists.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `build_conflict`         | 409     | A [template build](/agents-api/templates#build-an-image-in-the-cloud) `start` on a build that already started, or while another build is running in the workspace — one build runs at a time.                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `domain_exists`          | 409     | A [custom domain](/agents-api/domains) registration names a hostname already registered, by your workspace or any other.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `try_again`              | 409     | A transient state conflict: the instance is mid-transition, for example `stop` during the second or so while a sleep checkpoint is being written. Retry in a few seconds.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `no_capacity`            | 503     | Create only: no host can fit the requested shape right now. Safe to retry.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `image_ingest_failed`    | 502     | Registering a [template](/agents-api/templates) failed while copying the image into private storage, for a reason on our side (not a bad image). Retry, or contact [support@agent37.com](mailto:support@agent37.com).                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `provisioning_failed`    | 502/500 | A container or host operation failed (image pull, container start, lifecycle action). Creates debit nothing, so a failed create costs nothing.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |

<Note>
  Lookups are uniform: an id that belongs to another workspace returns the same 404 as an id that does not exist, and unknown `/v1` paths 404 only after your key is validated. Nothing about other workspaces leaks through error responses.
</Note>

A [template build](/agents-api/templates#build-an-image-in-the-cloud) that fails after starting is not an HTTP error: `GET /v1/template-builds/{id}` returns `200` with `status: "failed"` and the reason (`build_failed`, `build_timeout`, `invalid_request`, `invalid_image_archive`, `image_too_large`, `image_ingest_failed`, or `internal_error`) in its `error` field.

## Agent API errors

Errors from the gateway at `https://{instanceId}.agent37.app/v1/*` use the same envelope plus optional `param`, `hint`, and `response_id`.

```json theme={null}
{
  "error": {
    "code": "validation_error",
    "message": "goal mode is not yet supported on this gateway.",
    "param": "mode",
    "hint": "Use mode \"chat\"."
  }
}
```

<ResponseField name="error.param" type="string">
  The request field that was invalid. Present on `validation_error` when a specific field is at fault; a malformed JSON body has no `param`.
</ResponseField>

<ResponseField name="error.hint" type="string">
  A suggested next step, when one applies.
</ResponseField>

<ResponseField name="error.response_id" type="string">
  On `session_busy`: the id of the response already running on the session — reattach with `GET /v1/responses/{id}/stream` or cancel it. Treat it as optional; in a rare race the code arrives without it.
</ResponseField>

### Transport errors

Auth, instance lookup, and routing happen on the platform between you and the gateway, and rejections there use a flat string instead of the envelope: `{"error": "<code>"}`. Some carry a human-readable `message` (and, on a 401 with no credentials, a `docs` link); branch on the code, not on either. Check whether `error` is a string before reading `code`.

| Code                    | HTTP | When                                                                                                                                                                                                   |
| ----------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `invalid_api_key`       | 401  | No credential, or a key or signed URL that did not verify. The `message` says which, and how to authenticate a browser request.                                                                        |
| `instance_suspended`    | 402  | The instance is suspended for non-payment, so the request will not wake it. Top up the workspace wallet and retry.                                                                                     |
| `not_found`             | 404  | An instance URL that does not route: unknown, deleted, `failed`, or another workspace's.                                                                                                               |
| `container_unavailable` | 502  | The instance is not running, typically `stopped`. Start it and retry.                                                                                                                                  |
| `container_unreachable` | 502  | The instance is up but its service did not answer on the routed port — common briefly during a restart or update. Transient; retry.                                                                    |
| `upstream_unreachable`  | 502  | The platform could not reach the instance's host. Transient; retry.                                                                                                                                    |
| `instance_saturated`    | 503  | Too many concurrent requests in flight to this instance. Back off and retry.                                                                                                                           |
| `host_mesh_not_ready`   | 503  | The instance's host is still joining the platform network. Transient; retry.                                                                                                                           |
| `wake_timeout`          | 503  | A [wake](/agents-api/urls#sleeping-instances-wake-on-request) of a sleeping instance did not finish within about 60 seconds. It keeps waking in the background; retry.                                 |
| `wake_failed`           | 503  | A wake of a sleeping instance failed. It stays `sleeping`, and the next request tries again.                                                                                                           |
| `upstream_timeout`      | 504  | A call produced no response headers for \~100 seconds — typically a wedged instance. The turn may still be running: recover the result through its session, and prefer `stream: true` to see progress. |
| `internal_error`        | 500  | Unexpected platform error.                                                                                                                                                                             |

### Agent API codes

| Code                 | HTTP | When                                                                                                         |
| -------------------- | ---- | ------------------------------------------------------------------------------------------------------------ |
| `validation_error`   | 400  | A request field is invalid (`param` names it), the body is not valid JSON, or `mode` is `"goal"` (reserved). |
| `not_a_directory`    | 400  | `GET /v1/files?path=` points at something that isn't a directory.                                            |
| `response_not_found` | 404  | No response with that id.                                                                                    |
| `file_not_found`     | 404  | No file or directory at that path (`GET /v1/files`, `GET /v1/files/content`, `PATCH /v1/files`).             |
| `not_found`          | 404  | Unknown route on the instance URL.                                                                           |
| `rename_unsupported` | 405  | `PATCH /v1/sessions/{id}` against a harness that cannot rename sessions (no native editable title).          |
| `session_busy`       | 409  | A response is already running on this session; on the 409, `error.response_id` usually names it.             |
| `title_conflict`     | 409  | `PATCH /v1/sessions/{id}`: the requested title is already used by another session.                           |
| `file_exists`        | 409  | `PUT /v1/files/content` with `overwrite=false` when a file already exists at the path.                       |
| `modified`           | 412  | `PUT /v1/files/content` with `X-Expected-Mtime` when the file changed since you read it (lost-update guard). |
| `payload_too_large`  | 413  | A JSON request body exceeds 2 MB. The raw-body `PUT /v1/files/content` write is exempt.                      |
| `rate_limited`       | 429  | An upstream provider rate limit. Back off and retry.                                                         |
| `agent_error`        | 502  | The agent backend failed without a more specific code.                                                       |
| `agent_unavailable`  | 503  | The targeted harness is not available on this instance — not provisioned here, or down.                      |
| `internal_error`     | 500  | Unexpected gateway error.                                                                                    |

<Note>
  The Agent API catalog is open-ended past this table. Failures inside the agent can surface provider-specific codes at 502 or 503 (for example a provider auth or quota error passes its raw code through, and an agent that is still warming up returns 503 with its own code). Treat any code you do not recognize as an agent-side failure: log it and show `message`.
</Note>

<Note>
  Not every failed turn is an HTTP error. `POST /v1/responses` never rejects because the agent failed mid-run: the call returns 200 with `status: "failed"` and the same error object in the response body's `error` field, and streams end with a `response.failed` event. Check `status`, not just the HTTP code. See [Send a message](/agents-api/chat) and [Streaming](/agents-api/streaming).
</Note>

## Handle them

Read `code`, then act by remedy: busy sessions get a cancel or a new session, transient codes get a retry with backoff, validation errors get fixed (read `param`), and anything unknown is agent-side.

<CodeGroup>
  ```python python theme={null}
  import requests

  r = requests.post(
      "https://ab12cd34ef.agent37.app/v1/responses",
      headers={
          "X-Agent37-Key": "sk_live_...",
          "Content-Type": "application/json",
      },
      json={
          "input": "Research the top 3 EV makers, write a memo.",
          "session_id": "7f3e0b6c52a949d2b1c4a8e9d0f31726",
      },
  )

  if not r.ok:
      error = r.json()["error"]
      if isinstance(error, str):
          raise RuntimeError(f"transport error: {error}")  # flat platform error, e.g. container_unavailable
      code = error["code"]
      if code == "session_busy":
          ...  # cancel the running response or start another session
      elif code == "rate_limited":
          ...  # transient: back off and retry
      elif code == "validation_error":
          raise ValueError(f"{error.get('param')}: {error['message']}")
      else:
          ...  # unknown codes are agent-side failures: log code, show message
  ```

  ```javascript node theme={null}
  const res = await fetch("https://ab12cd34ef.agent37.app/v1/responses", {
    method: "POST",
    headers: {
      "X-Agent37-Key": "sk_live_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      input: "Research the top 3 EV makers, write a memo.",
      session_id: "7f3e0b6c52a949d2b1c4a8e9d0f31726",
    }),
  });

  if (!res.ok) {
    const { error } = await res.json();
    if (typeof error === "string") {
      // flat platform error, e.g. "container_unavailable": see the transport table
      throw new Error(`transport error: ${error}`);
    }
    switch (error.code) {
      case "session_busy":
        // cancel the running response or start another session
        break;
      case "rate_limited":
        // transient: back off and retry
        break;
      case "validation_error":
        throw new Error(`${error.param}: ${error.message}`);
      default:
        // unknown codes are agent-side failures: log code, show message
        console.error(error.code, error.message);
    }
  }
  ```
</CodeGroup>

The same grouping works on the Hosting API: `insufficient_balance` sends your user to the billing dashboard, `no_capacity` is retryable, and `invalid_request` means fix the request before retrying.

<Tip>
  `no_capacity` (503, hosting) and `rate_limited` (429, agent) are safe to retry with backoff. So are `try_again` (409, hosting) and a `provisioning_failed` create: creates debit nothing (the meter only starts once the instance runs), so retrying never double-bills.
</Tip>

## Codes worth a closer look

<AccordionGroup>
  <Accordion title="insufficient_balance (402): the workspace wallet is empty" icon="wallet">
    The workspace wallet cannot cover a charge. You see it in three places: at create, when the wallet holds less than one day of the instance's running rate (a check, not a debit; the meter only starts once the instance runs); at `start`, when a `past_due` instance's workspace balance is still negative; and inside agent behavior, when a managed call (LLM, Brave search, Composio) finds the wallet empty. The fix is the same everywhere: top up the wallet at `https://www.agent37.com/dashboard/cloud/billing` (\$5 minimum, \$1000 max per top-up), and enable [automatic top-up](/agents-api/billing#automatic-top-up) so it does not recur. See [Billing](/agents-api/billing).
  </Accordion>

  <Accordion title="instance_budget_exhausted (402): this instance hit its budget" icon="gauge">
    The wallet has funds, but this instance has used up its own managed-spend budget: the monthly cap is consumed and no one-time top-up headroom remains. Only managed calls are refused; the instance keeps running and compute billing is unaffected. Raise the cap with `PATCH /v1/instances/{id}/budget` or add headroom with `POST /v1/instances/{id}/budget/top-up`. See [Budgets](/agents-api/budgets). You will not see this code on Hosting API calls: it surfaces when the agent's managed calls are refused mid-turn.
  </Accordion>

  <Accordion title="session_busy (409): one response at a time" icon="clock">
    A session runs one response at a time. Posting new input while a turn is in flight returns this, usually with the running response's id in `error.response_id`. Three ways out: reattach to the running turn with `GET /v1/responses/{response_id}/stream`, cancel it with `POST /v1/responses/{response_id}/cancel` (best effort; a finished response just returns its terminal state), or start a fresh session by omitting `session_id`. If the field is absent (a rare race, or an older gateway), read `active_response_id` from `GET /v1/sessions/{id}` instead. See [Sessions](/agents-api/sessions).
  </Accordion>

  <Accordion title="The capacity trio: instance_limit_reached, capacity_unavailable, no_capacity" icon="server">
    Three different walls, three different fixes. `instance_limit_reached` (409, create): the workspace is at its instance limit (one instance on the free credit, 10 once you have topped up, 50 once top-ups total \$500); delete instances you no longer need, or email [vishnu@agent37.com](mailto:vishnu@agent37.com) to raise the ceiling. `no_capacity` (503, create): no host can fit the requested shape right now; retry with backoff or pick a smaller shape, and a create that fails this way does not keep your money. `capacity_unavailable` (409, start or resize): the host that holds the instance's disk cannot fit it, and no other host has room to take it either (when the home host is full, the platform moves the instance to one with room before it ever fails); retry later. See [Instances](/agents-api/instances).
  </Accordion>
</AccordionGroup>

<Note>
  Both 402 reasons are billing limits, not bugs. When a managed call is refused mid-turn, the refusal shows up in agent behavior (the turn fails or the agent reports it); the instance itself never goes down over managed spend.
</Note>
