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

# Errors

> Every error code the Managed Agents API returns, grouped by area, with its cause, the fix, and whether retrying can help.

Every failed request returns the same JSON shape with a stable `code`. Branch on `code`, never on `message`. This page lists every code you can receive, what causes it, and whether to retry.

## The error shape

```json theme={"theme":"css-variables"}
{
  "code": "idempotency_in_progress",
  "message": "a request with this Idempotency-Key is already in progress",
  "details": {
    "field": "Idempotency-Key",
    "requestId": "0b6f2c1d-9a4e-4b7f-8c3d-5e6a7b8c9d0e"
  }
}
```

| Field | Use |
| - | - |
| `code` | Stable and machine-readable. Branch on this. |
| `message` | For people. It can change at any time. |
| `details` | Code-specific context, such as `field`, measured values, limits, or the next call to make. |
| `details.retryable` | `true` when the same request can succeed later, and `false` when it must not be retried. When omitted, follow the operation's generated retry strategy in **Endpoints**. |
| `details.requestId` | Include this, and the `x-request-id` response header, when you report a problem. |

## How to retry

The operation's generated retry strategy in **Endpoints** decides whether replay is allowed. `Retry-After` only says when to make an allowed retry; it never grants retry permission.

| Situation | What to do |
| - | - |
| `Retry-After` header present | If the operation's strategy permits replay, wait that long before retrying. It's sent with some `409` and `429` responses. |
| `details.retryable: true`, no `Retry-After` | If the operation's strategy permits replay, retry with exponential backoff and jitter, starting around one second. |
| `5xx` on a keyed mutation | Retry only when the operation's strategy permits it, using the same `Idempotency-Key` and exact request bytes. |
| Any other `4xx` | Don't retry unchanged. Fix the request first. |

## Request and validation

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `400 invalid_request` | A field, query parameter, or header is missing, malformed, or out of range. `details.field` names it. Also returned when the body isn't valid JSON, a tenant-scoped key omits `x-organization-id`, `Idempotency-Key` is malformed or repeated, or a `page_token` has expired or doesn't match the query. Session-list tokens last one hour. | Fix the named field. For a `page_token`, restart the list without it. | No |
| `400 invalid_json` | The body is JSON but doesn't match the operation's schema, such as a field with the wrong type. `details.field` names the field when it's known. | Check the body against **Endpoints**. | No |
| `413 payload_too_large` | The body is bigger than the operation accepts, for example a skill bundle over 8 MiB or an `uploadFile` file part over 30 MiB. | Send a smaller body. | After fixing |
| `415 unsupported_media_type` | The body's media type isn't accepted. Skill bundles and `uploadFile` use `multipart/form-data`; other request bodies use JSON. | Use the operation's declared media type. | No |

## Authentication and access

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `401 unauthorized` | No API key, or the key is malformed, expired, revoked, or no longer active. | Check the `Authorization: Bearer` header. See [API keys](/recursion/api-keys). | No |
| `403 forbidden` | The key is valid, but your role in the organization doesn't allow this operation. | See [Organizations and roles](/recursion/organizations-and-roles). Use an account or key with the developer or admin role. | No |
| `403 session_start_not_admitted` | New work was refused. With `details.reason: "out_of_credit"`, your tenant has used its credits, so new sessions and messages that start a turn are refused. A session that is already running pauses before its next model request, with `stop_reason: out_of_credit`. With `details.reason: "tenant_suspended"`, your account is suspended and its running sessions pause with `stop_reason: tenant_suspended`. | Out of credit: buy credits, then start the session or send the message again. See [When credits run out](/recursion/billing#when-credits-run-out). Suspended: contact support. | After a top-up, or once support restores the account |
| `403 setup_run_not_admitted` | A setup test was refused before it was recorded. With `details.reason: "out_of_credit"`, your tenant has used its credits; with `details.reason: "tenant_suspended"`, your account is suspended. | Out of credit: buy credits, then test setup again. See [When credits run out](/recursion/billing#when-credits-run-out). Suspended: contact support. | After a top-up, or once support restores the account |
| `503 setup_run_admission_unavailable` | The setup test's credit check could not be completed; no run was recorded. | Retry the same request with the same `Idempotency-Key`. | Yes |
| `404 not_found` | The resource doesn't exist, or it's in an organization you can't reach. Also returned for an `x-organization-id` you can't use, and for any path the API doesn't serve. The cases look the same on purpose. | Check the id, the path, and the organization. | No |
| `503 service_unavailable` | Your key couldn't be checked right now. The request did not run. | Retry shortly. | Yes |

## Conflicts and concurrency

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `409 conflict` | The request conflicts with the resource's current state, such as a duplicate name, or deleting a session while its hard stop is still finishing. | Read the resource, then change the request. | Only when `details.retryable` is `true`. |
| `409 revision_conflict` | Someone published a newer agent or skill version after you read it, or an environment's settings changed while your update was saving. | Read it again, apply your change to the latest version, and retry. | After re-reading |
| `412 precondition_failed` | An environment update sent `expected_access` that no longer matches its network policy or privileged access. | Read the environment and retry with its current access settings. | After re-reading |
| `428 precondition_required` | An update changes an environment's stored network policy, or turns on privileged access, without `expected_access`. | Read the environment and send its current access settings as `expected_access`. | After re-reading |
| `412 precondition_failed` on `If-Match` | An automation, event source, or its public representation contract changed after you read it. | Read it again and retry with its new returned ETag. | After re-reading |
| `428 precondition_required` on `If-Match` | A replace, pause, resume, or delete of an automation or event source sent no `If-Match`. | Send the complete returned `ETag` from the current read as `If-Match`; do not construct it from `revision`. | After fixing |

## Idempotency

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `409 idempotency_conflict` | The `Idempotency-Key` was already used for a different request. | Use a new key for a new request. Resend the exact same bytes to replay. | No |
| `409 idempotency_in_progress` | The first request with this key is still running. | Wait for `Retry-After`, then send the same request again. | Yes |
| `503 idempotency_unavailable` | The key couldn't be checked or reserved. The request did not run. | Retry with the same key. | Yes |

See [Idempotent mutations](/recursion/api#idempotent-mutations).

## Rate limits and capacity

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `429 rate_limit_exceeded` | You sent too many requests. The limit is per allowance: all your API keys share one, and console use has its own. | Wait for `Retry-After`. | Yes |
| `429 rate_limited` | Your organization's request rate limit is exhausted. | Wait for `Retry-After`. | Yes |
| `429 tenant_concurrency_limit` | Your tenant already has as many working root sessions as it may. `details.limit` is the cap. | Wait for `Retry-After`, or for a session to finish its turn. | Yes |
| `429 setup_run_limit` | Your organization has as many setup runs in flight as it may. `details.limit` is the cap and `details.in_flight` lists the runs. | Wait for a run to finish, or cancel one. | Yes |
| `503 service_unavailable` | The service is briefly unavailable, or at event-stream capacity. | Retry with backoff. For streams, close ones you no longer need. | Yes |

## Environments and setup

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `422 environment_not_verified` | The environment's setup script has never passed, failed, changed since it passed, or is still being tested. `details.next_action` names the call to make. | Run a setup test and wait for it to pass. See [Environments](/recursion/environments). | Yes, while a test is running |
| `422 sandbox_provider_disabled` | The request names a runtime this deployment doesn't offer for new work. | Use the **Agent runner** runtime (`runs`). | No |
| `409 setup_run_in_progress` | A setup run is already in flight for this environment. `details.setup_run_id` names it. | Wait for it to finish; a manual run or automatic runner refresh can be cancelled by a member allowed to update the environment. | After it ends |
| `409 setup_run_finished` | You tried to cancel a setup run that had already finished. Nothing changed. | None needed. | No |
| `503 setup_run_not_started` | The setup run was recorded but couldn't start. It's marked failed. | Start another setup run. | Yes |

## Integrations

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `400 invalid_request` on `resources` or `permission` | A tool allow-list is empty, has more than 200 tools, names a tool the app doesn't have, or holds a tool that isn't read-only under the `read` preset. | Send 1 to 200 tool names from the catalog, or use `permission: "write"`. See [Integrations](/recursion/integrations#change-an-apps-tools). | No |
| `400 invalid_request` on `built_in_integrations` | An agent names more than 25 apps, sends `tools`, or names a connection that isn't an active built-in integration with at least one tool. | Fix the entry `message` describes. See [Grant apps to an agent](/recursion/integrations#grant-apps-to-an-agent). | No |
| `422 provider_selection_unsupported` | A tool allow-list change was sent for a native integration, whose access is set per agent. | Set the access on the agent instead. | No |
| `503 built_in_catalog_unavailable` | The app catalog couldn't be loaded. | Retry. | Yes |
| `503 built_in_integrations_unconfigured` | The app catalog couldn't be reached for your organization. | Contact support. | No |
| `503 integrations_unconfigured` | The integration service couldn't be reached. | Retry later. If it persists, contact support. | Yes |
| `429 github_rate_limited` | GitHub is limiting requests made for your connection. | Retry after `Retry-After`. | Yes |
| `503 github_unavailable` | GitHub couldn't be reached. | Retry later. | Yes |

A connection test that fails still returns `200`, with `ok: false` and a `failure` reason. See [Test a connection](/recursion/integrations#test-a-connection).

## Files

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `413 payload_too_large` on `uploadFile` | The file part is over 30 MiB, or the complete multipart request exceeds the file limit plus its 128 KiB framing and form-field allowance. | Upload a file of at most 30 MiB through the API, or use the console for a larger file. | After fixing |
| `413 file_quota_exceeded` | The upload would take your organization's live files past its storage quota. `details` has `quota_bytes`, `used_bytes`, and `incoming_bytes`. | Set expiries on uploads so they stop counting once they expire. | After fixing |
| `404 not_found` on `file_id` | The file doesn't exist in your organization, or it expired. | Use a live file id. | No |
| `409 conflict` on `resources` | An attachment path collides with another, or the session isn't the root of its tree. | Choose another `relative_path`, or attach to the root. | After fixing |

See [Files](/recursion/files).

## Automations and event sources

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `422 automation_reference_invalid` | The automation's agent version or environment doesn't exist or can't be used. | Choose a live agent version and a verified environment. | After fixing |
| `422 automation_event_source_invalid` | A trigger names a missing or incompatible event source. | Use a source of the trigger's type. | After fixing |
| `422 event_source_verification_credential_invalid` | A signed custom source names a verification credential that isn't a live signing secret in your organization. | Name a live signing secret from your organization, or keep the source's current one. | After fixing |
| `409 conflict` on `eventSourceId` | The source is still used by automations, or it's managed by its connection. | Remove it from triggers first, or manage it through its connection. | After fixing |
| `503 event_admission_unavailable` | A webhook delivery couldn't be recorded. Returned to the sender. | The sender retries. | Yes |

A run that can't start its session ends `failed` with an `error` that has its own `code`, `message`, and `retryable`. See [Automations](/recursion/automations#see-run-history).

## Models and the session analyst

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `503 model_gateway_unreachable` | The model list, or the model a request names, couldn't be checked right now. | Retry later. | Yes |
| `503 session_analyst_busy` | Another request to the same session analyst was still running. | Retry. | Yes |
| `503 session_analyst_model_unavailable` | The session analyst's model isn't available. | Retry later. | Yes |
| `503 session_analyst_unconfigured` | The session analyst couldn't be started for your organization. | Contact support. | No |

## Server errors

| Status and code | Cause | Fix | Retry? |
| - | - | - | - |
| `500 internal_error` | An unexpected failure. Details are withheld. | Retry once with the same `Idempotency-Key` if it was a create. If it persists, report `details.requestId`. | Once |
| `500 invariant_violation` | An internal consistency check failed. Details are withheld. | Retry once. If it persists, report `details.requestId`. | Once |
| `502 bad_gateway` | An internal service returned an invalid response. | Retry with backoff. | Yes |
| `503 managed_agents_unavailable` | Managed Agents is temporarily unavailable. | Retry with backoff. | Yes |
| `504 gateway_timeout` | The request took too long. It may or may not have run. | Retry creates with the same `Idempotency-Key`. Read the resource before retrying other writes. | Yes |
| Any other `503` code | A service dependency is temporarily unavailable. | Retry with backoff. If it persists, report `details.requestId`. | Yes |

## Session failure codes

A session that fails has a `failure` object. These codes are separate from HTTP errors: the request that started the session succeeded, but the work later stopped.

```json theme={"theme":"css-variables"}
{
  "status": "failed",
  "failure": {
    "code": "sandbox_provision_timeout",
    "phase": "provisioning",
    "category": "transient",
    "retryable": true,
    "message": "Agent runner provisioning timed out. The session may succeed when capacity recovers."
  }
}
```

Read `category` first:

| `category` | Meaning | What to do |
| - | - | - |
| `transient` | A temporary condition. | Send a follow-up message to resume, or start again later. |
| `caller_error` | Something in your request or configuration. Retrying as is won't help. | Fix the agent, environment, or grant, then resume or start a new session. |
| `internal` | A problem on our side. | Report the `session_id`. |

| `failure.code` | Cause | Fix |
| - | - | - |
| `sandbox_provision_timeout` | Compute wasn't ready within 5 minutes. | Resume or start again. |
| `sandbox_capacity_unavailable` | Compute capacity was temporarily unavailable. | It's retried automatically. If it persists, try again later. |
| `sandbox_image_pull_failed` | The image saved by the environment's last passing setup test couldn't be loaded. | None. It's retried automatically without rerunning setup. |
| `sandbox_configuration_invalid` | The environment's settings can't be run. | Fix the environment. `message` says what's wrong. |
| `sandbox_provider_unavailable` | The runtime was briefly unavailable. | Resume or start again. |
| `sandbox_gpu_not_ready` | The GPU didn't pass its readiness check. | Report it. Starting again usually reproduces it. |
| `environment_setup_failed` | The environment's setup failed while preparing the session. | Check the linked setup run, fix the script if it failed, and test setup again. See [Environments](/recursion/environments). |
| `credential_resolution_failed` | A granted credential couldn't be opened. | Check the session's vault grants and that the credentials still exist. |
| `model_not_found` | The agent's model isn't available. | Update the agent to a model from `listModels`. |
| `model_authentication_failed` | The model provider rejected the platform's credential for the model. | None on your side. Choose another model or try later, and report the `session_id`. |
| `model_rate_limited` | The model provider throttled the requests. | Resume later. |
| `model_provider_unavailable` | The model provider was unavailable. | Resume later. |
| `model_request_failed` | The model provider rejected a request. | Check the agent's model settings, such as reasoning effort. |
| `model_prompt_cache_invalid` | The agent's prompt-cache retention settings are invalid or unsupported for its model. No model request was sent. | Clear or correct the agent's prompt-cache retention settings, then start a new session. |
| `model_reasoning_capacity_invalid` | The reasoning effort doesn't fit the model's output capacity. | Lower the agent's reasoning effort or choose another model. |
| `model_refused` | The model declined to continue the task. | Change the task or instructions. Resuming repeats the refusal. |
| `roster_agent_unresolved` | A subagent in the roster names an agent, version, or model that doesn't exist. | Fix the roster. See [Multi-agent](/recursion/multi-agent). |
| `worker_replaced` | A service update interrupted the work. | Send a follow-up message to resume if the session is still stopped. |
| `repository_provider_unavailable` | The repository host was unavailable. | Resume later. |
| `internal_error` | An unexpected failure. | Report the `session_id`. |

Setup runs report the same failure vocabulary in their `failure_code`.

## Next steps

<CardGroup cols={2}>
  <Card title="Troubleshooting" href="/recursion/troubleshooting">
    Match a symptom to its cause and fix.
  </Card>

  <Card title="Limits" href="/recursion/limits">
    See the limit behind each size or rate error.
  </Card>

  <Card title="API conventions" href="/recursion/api">
    Retries, idempotency, and paging.
  </Card>

  <Card title="Event types and states" href="/recursion/reference">
    Look up session statuses and stop reasons.
  </Card>
</CardGroup>
