Home / Docs / Errors

Errors reference

Every status the REST API answers with and every error code the MCP server returns, what it means, and what to do. Statuses come from /openapi.json; MCP codes from the server's JSON-RPC mapping.

Error body

REST errors carry the same JSON body as the E2B API: {"code": <http status>, "message": "..."}. Extra fields appear only where they help:

HTTP statuses

StatusMeaningWhat to do
400The request is malformed: invalid JSON body, a field of the wrong type, an out-of-range value (limit outside 1 to 100, timeout_s outside 1 to 3600), an unsupported filter or order value, a bad nextToken, or an invalid network or port update.Fix the request. The message names the field. Do not retry unchanged.
401Missing, invalid or revoked API key (X-API-Key); on the sandbox host, a missing or wrong X-Access-Token or port token.Send the key in X-API-Key. Get a key from the console. For sandbox-host calls use the envdAccessToken from the create response.
402Credit exhausted: credit exhausted; add credit to resume. New sandboxes and resumes are refused until the key has credit again. This is always about your key’s credit: a platform-side budget problem answers a retryable 503 platform_capacity instead. On the sandbox data plane (the stock SDKs' envd Connect calls: process start and input) the 402 body is a Connect error with code: failed_precondition and error_code: credit_exhausted, so SDK clients see a typed Code.FAILED_PRECONDITION instead of Code.UNKNOWN.Do not retry; the message says what to do. Check GET /v0/usage, add credit or contact support (see limits).
403The key is not allowed to do this: the tenant is suspended or the sandbox is paused for an abuse-policy violation, or the feature is not on your tier (for example GPU sandboxes when the free GPU trial is switched off), or a free-tier GPU request beyond the trial (gpu_free_tier_limit, below).Do not retry unchanged. For gpu_free_tier_limit, lower the request or lift the limit as its message says. Otherwise read the acceptable use policy; contact us if you think it is wrong.
404The sandbox, snapshot, template, webhook, prompt or job does not exist, or is not yours. The two cases look identical on purpose. A killed or retention-expired sandbox is a 404 too.Check the id and the key. A deleted sandbox cannot be resumed: create a new one.
409The request conflicts with current state: a snapshot was deleted while being created or cancelled by a shutdown; a card is already verified; the key is not on the self-serve free tier; a GPU lease operation conflicts with the lease's state.Re-read the state, then retry only if it still makes sense.
413The request body is too large (waitlist, claim or GPU lease upload). GPU uploads are capped independently by front and node, default 512 MiB. A body sent to a sandbox port URL (<port>-<id>.sbx.agent-next.com) is capped at 2 GiB by the edge proxy.Send a smaller body, or split the upload.
507The gateway could not write a GPU lease upload, for example because its disk is full. The previous destination file stays intact.Do not retry continuously; report persistent storage failures.
429Rate or quota limit. The running-sandbox quota names both numbers (running, limit): concurrent running sandbox quota exceeded. Also paused sandbox quota exceeded, a prompt limit per sandbox (live, limit), too many pending snapshots, too many signup or card-verification requests.Wait Retry-After seconds and retry. For a concurrency cap, kill finished sandboxes first.
499The client disconnected before the answer was ready. The gateway discards work it had not finished.Nothing to fix on the server. Re-list before retrying a create, in case it completed.
500A platform failure the node reported (for example a failed sandbox create), with a generic message and an error_id. Also POST /v1/stripe/webhook: processing failed and Stripe will retry.Not a client error. Retry a create with the same Idempotency-Key so a retry cannot start a second sandbox. If it persists, quote the error_id.
501this E2B feature is not supported in beta: a call to an E2B route the gateway does not implement (see unsupported features).Do not retry. Use a supported call.
502A platform failure: the node returned something malformed or could not resume a sandbox. Carries status; carries error_id when the node answered with a 5xx the gateway replaced.Retry with backoff. If it persists across sandboxes, check the status page and quote the error_id.
503Temporarily unavailable. node at capacity: too many sandboxes running or starting; retry later; host disk nearly full; platform capacity (the sandbox backend refused the call on the platform’s side — error_code: platform_capacity); no GPU class or GPU capacity budget available; or a feature that is not configured on this gateway.Retry after Retry-After seconds. A 503 on create is safe to repeat.
504The node did not answer in time (upstream did not respond in time).Retry with backoff. Check that the sandbox is still running before repeating a non-idempotent command.

The error_code field

error_codeStatusMeaning and fix
credit_exhausted402Data plane: the key has no running-hours credit left, so new process work (commands, PTY input) and traffic that would wake a paused sandbox are refused. Existing work keeps its grace period; output reads still answer while it runs. Add credit (or wait for the reaper's pause), then retry — the body's code is the Connect code failed_precondition, so the stock SDKs raise a typed Code.FAILED_PRECONDITION, not Code.UNKNOWN.
gpu_credit_exhausted402GPU plane: the key has used its monthly GPU allowance and any operator-granted GPU credit. Check GET /v0/usage; wait for the monthly allowance to reset or obtain more GPU credit before retrying.
gpu_lease_cap409GPU plane: the key has reached its tier's simultaneous GPU lease limit. Paused leases still count. On a node fleet a dead lease stops counting once its node lists it dead or no longer lists it; one on a node that cannot be read keeps counting. Destroy a lease before creating another.
gpu_class_unavailable400GPU plane: accel.class names a card no GPU node serves right now, so nothing was placed. The message lists the classes that are served, which GET /v0/gpu/capacity also shows. Create with one of them, or leave accel.class out and the reply names the class you got. While a node did not answer, or lists no class, the same request is a retryable 503 instead, because that node may be the one serving the class. A class the operator rents on demand is not a 400 either: see gpu_class_provisioning and gpu_class_no_supply.
gpu_class_provisioning503GPU plane: accel.class names a card no GPU node serves yet, but the operator rents it on demand and a node for it has been requested. Retry the same request after the Retry-After seconds (the body's eta_s is the same estimate), or create with accel.wait_s to have the create wait for the node.
gpu_class_no_supply503GPU plane: accel.class names a card the operator rents on demand, but the provider reported no stock of it within the last ten minutes, so no node is on its way. The body's alternatives lists the classes served now, which GET /v0/gpu/capacity also shows. Create with one of them, or retry the same request after Retry-After (300 seconds).
gpu_free_tier_limit403GPU plane: a free-tier key asked for more than the free GPU trial allows: a slice over the cap (2 GiB by default), accel.network: "internet", an accel.class outside the free-tier list (nvidia.5090 by default), an accel.template other than the default template, or an accel.idle_timeout_s of 0 or over 600 s (a free sandbox keeps its idle auto-pause). The body's param field names the request field (accel.vram_gb, accel.network, accel.class, accel.template or accel.idle_timeout_s) and the message gives the allowed value. Create within the limit, or contact support to lift it (the message names card verification only while GET /v1/tiers reports card_verification_enabled). GET /v1/tiers has the live free-tier numbers.
quota_running_exceeded429Your key already has its maximum number of running sandboxes. Kill or pause one, then retry after Retry-After. The cap is limits.max_concurrent in GET /v0/account.
quota_paused_exceeded429Your key already holds its maximum number of paused sandboxes, so another cannot be paused. Kill paused sandboxes you no longer need.
upstream_profile_unsupported501This deployment's sandbox backend does not support snapshots or forks, so the call was refused before anything changed. Do not retry; create a fresh sandbox instead.
prompt_concurrency_exceeded429The sandbox already has the maximum number of live managed prompts. Wait for one to finish (GET /sandboxes/{id}/prompts/{prompt_id}).
owner_lease_cap409GPU plane: you already hold your maximum number of GPU leases. Release one. It is a cap on your key, not a lack of free GPUs.
gpu_egress_disabled400GPU plane: you asked for accel.network: "internet" but no GPU node has internet egress turned on. Create without it (the default "none"), or ask the operator to enable egress.
gpu_egress_firewall_pending503GPU plane: the node allows internet leases, but its egress firewall is not verified right now, so the lease was refused rather than started unprotected. Retry later; other nodes are tried first.
gpu_slice_too_large400GPU plane (single plane only): the slice is larger than the card can seat even empty (its total VRAM less the plane's fixed reserve), so nothing is parked or created and no retry clears it. The message names the largest slice that does seat — lower accel.vram_gb or accel.tier. Momentary VRAM pressure is never this 400: a slice the empty card seats gets the retryable gpu_capacity_exhausted. A node fleet never answers it: no front can know that no node will ever seat the slice, so a slice every node it was offered to refused keeps the retryable 409 gpu_capacity_exhausted, its message naming the largest slice an answering node seats.
gpu_capacity_exhausted503 or 409GPU plane: no seat is free right now (503 on the local plane or when a node refuses an exec; 409 when the node fleet is full or a node refuses a resume). The body carries retry_after_s and class, and a Retry-After header. Wait that long and retry; GET /v0/gpu/capacity shows the free seats first. See the GPU guide.
gpu_fair_share429GPU plane: your key held the GPU past its streak while another tenant is waiting. The body carries retry_after_s and class, and a Retry-After header. Wait and retry.
gpu_global_budget503GPU plane: every key’s billed GPU-seconds together have passed the beta’s fleet-wide GPU-hour cap, so no create is admitted. The body carries retry_after_s (300), class and a Retry-After header. The cap is cumulative, not a window: waiting does not clear it, and only an operator raising it does. Retry on that interval, not in a tight loop; a lease you already hold still execs and resumes. See the GPU guide.
gpu_job_timeout409GPU plane: the job outlived its timeout_s and the lease was killed. The reply carries error_code only: no error field and no Retry-After. DELETE /sandboxes/{id} the dead lease, create a new lease and run the job again with a larger timeout_s.
gpu_lease_dead409 or 503GPU plane: the lease is gone. It died (409, which carries error_code only), or the exec reply was lost and the lease destroyed (503). DELETE /sandboxes/{id} the lease (a 404 means it is already destroyed), create a new lease and run the job again.
gpu_node_busy503GPU plane: the GPU node was starting or stopping a container and could not answer a capacity read (GET /v0/gpu/capacity), a lease list or a drain call within 5 s, or 128 such calls were already waiting. Nothing was applied: a refused drain has changed nothing, and a fleet front reads the node as not answering that probe. The answer carries retry_after_s and a Retry-After header (Retry-After: 5); the GET /v0/gpu/capacity answer also carries class. Wait and retry.
gpu_node_draining503GPU plane: the GPU node is being drained and takes no new lease. A fleet front tries the other nodes first and answers this same retryable 503 (Retry-After: 30) when no active node took the create and a draining one had room for it. The body carries retry_after_s and class, and a Retry-After header. Wait and retry.
gpu_node_unreachable503GPU plane: the GPU node could not be reached, or answered 503 without a code, or a create named an accel.class that no answering node lists while another node did not answer or lists no class (it may serve that class), or no answering node lists any accel class yet (class discovery failed, retry_after_s 30). The body carries retry_after_s and class, and a Retry-After header. Wait and retry.
gpu_worker_boot_failed503GPU plane: the worker hit a transient CUDA init race on all 3 boot tries (the plane retries them itself). The body carries retry_after_s and class, and a Retry-After header. Wait that long and retry.
idempotency_in_progress409A create with this Idempotency-Key is still running; a concurrent request owns it. Wait the Retry-After seconds, then repeat the same request: it replays the finished answer or reports progress.
idempotency_key_reused409The key was already used with a different request body. Send a fresh key for each distinct request; do not retry the same key with changed fields.
idempotency_unresolved503An earlier create with this key ended without a known outcome and the gateway is reconciling it. Retry the same request with the same key after Retry-After; a new key can duplicate the sandbox.
upstream_unconfirmed502The upstream did not confirm the sandbox is gone (one 404, the confirmation check disagreed — e.g. mid platform incident). The sandbox is not deleted: retry after Retry-After; it stays reachable.
platform_capacity503The sandbox backend refused the call on the platform’s side (on 2026-10-09 its own running-hours budget was used up, so every tenant’s calls were refused at once). Your key’s credit is not the problem and nothing needs fixing on your side. Retry after Retry-After (60); a create is safe to repeat. The body carries error_id — quote it if you report it.

MCP errors

Every MCP JSON-RPC error carries a hint.

The MCP server (POST /mcp and /mcp/v1) reports tool and protocol errors as a JSON-RPC error with HTTP status 200: {"jsonrpc":"2.0","id":1,"error":{"code":-32602,"message":"..."}}. A success has result.structuredContent and isError: false. In-band failures are normal results with isError: true and a structuredContent like {"error_code": "NOT_FOUND", "retryable": false, "message": "..."}: a tool call on a sandbox, job or file that does not exist (or belongs to another key), and sandbox_files_read on a directory (error_code: "IS_DIRECTORY", same shape). Authentication failures are plain HTTP, before JSON-RPC starts.

CodeMeaningWhat to do
-32700Parse error: the body is not valid JSON.Send one JSON-RPC object.
-32600Invalid request: the body is JSON but not an object.Send an object with jsonrpc, id, method.
-32601Method not found. Supported: initialize, tools/list, tools/call, resources/list, resources/templates/list, resources/read.Use one of those methods.
-32602Invalid params: an unknown tool, a missing or malformed argument (missing argument 'sandbox_id'), or a value out of range (port outside 1 to 65535, a bad sandbox_id).Fix the arguments. Run tools/list for the schemas.
-32603Internal error: an unexpected failure inside the server.Retry once. If it repeats, report the message.
-32000The tool ran and the operation failed. The message is the REST message, with quota detail appended where it applies (limit 2 reached; 2 in use; retry in 5s). Also: a polling timeout (sandbox_exec_output timed out; poll again), or a sandbox with no usable envd token.Treat it like the matching REST status above. A command that outlives timeout_s is not an error: sandbox_exec returns a normal result with status timeout, exit_code 124 and timed_out true. For a timed-out poll, call sandbox_exec_output again with the same job_id. For a missing token, kill and recreate the sandbox.
-32002Not found: sandbox not found or job not found. Another tenant's sandbox looks the same. For a tool call it is not sent as a JSON-RPC error: it arrives as the isError: true result with error_code NOT_FOUND described above. resources/read with an unknown URI does return this JSON-RPC error (resource not found).Check the id; do not retry (retryable is false). Calling sandbox_kill again on a gone sandbox is safe.

HTTP-level MCP failures: 401 for a missing or invalid key (send X-API-Key or Authorization: Bearer), and 403 when an OAuth token lacks the sandbox scope.

See also: limits · quickstart troubleshooting · openapi.json