Errors
Every error code the gateway sends, the Python exception it becomes, and what to do about it.
Shape
Every non-2xx reply has the same flat JSON body and an X-Request-Id header with the same id:
JSON
{
"error": "the computer is gone",
"code": "env_gone",
"request_id": "gw_01M6KT15Q5ARXA5Y6HWVCHYHKP",
"details": {"drumsd_code": "env_gone"},
"closed_reason": null
}| Field | Meaning |
|---|---|
error | A short, fixed message. Never the runtime's raw output, never a host path |
code | Machine-readable code (table below). Branch on this, not on error |
request_id | gw_ followed by a time-ordered id. Include it when you contact your platform operator |
details | Present for some codes: state for wrong_state, limit and value for quota_exceeded, drumsd_code for runtime refusals |
closed_reason | Only on 410 env_gone: why the computer was closed, when known |
401 replies also carry WWW-Authenticate: Bearer realm="drums"; 429 replies carry Retry-After (seconds).
Codes
| Status · code | SDK exception | Meaning | What to do |
|---|---|---|---|
| 400 invalid_request | BadRequest | The request is malformed: an unknown body field, a wrong type, a value out of range, or a body over 4 MiB. | Fix the request. The message names the field. |
| 401 unauthenticated | AuthError | The key is missing, malformed, unknown, revoked or expired; or its owner left the workspace; or the workspace is suspended. | Check DRUMS_TOKEN. Create a new key under API Keys if it was revoked or expired. |
| 403 forbidden | DrumsError (status 403) | The key lacks the route's scope, or the call is not allowed for this resource (e.g. deleting a base image). | Create a key with the needed scope. Effective scopes never exceed the key owner's role. |
| 403 quota_exceeded | DrumsError (status 403) | A workspace or host limit would be exceeded: live computers, fork size, saved states. details.limit names it. | Close computers or delete saved states, or ask a workspace owner to raise the limit. |
| 403 budget_exceeded | DrumsError (status 403) | The workspace spend cap for the period (or a run's budget) is reached. | Ask a workspace owner. Not retryable until the period resets or the cap changes. |
| 404 not_found | NotFound | No such route, task, image, saved state or computer in your workspace on this host. | Check the id. Ids of other workspaces are always 404. |
| 409 wrong_state | Conflict | Not allowed in the computer's current state (e.g. a step on a quarantined computer). details.state has the state. | Release and reset a quarantined computer, or close it and create another. |
| 409 not_quiescent | NotQuiescent | Save or fork found no moment when the process tree was quiet within the timeout. Nothing was captured. | Retry, or pass a longer quiesce_timeout. |
| 409 checkpoint_stale | CheckpointStale | The image's checkpoint does not match the runtime (e.g. after a runtime change or a host reboot). | Contact your platform operator; the host must re-provision the image. |
| 410 env_gone | EnvGone | The computer is closed: by a client, by its lifetime or idle lease, or by a spend cap. closed_reason says why when known. | Create a new computer. Do not retry. |
| 422 task_unsupported | TaskUnsupported | The task needs the agent itself to act as root, which desktops never allow. Nothing was started. | Pick a task with supported: true. |
| 422 unsupported_runtime | BadRequest | The template no longer matches its manifest, the host runtime is not an approved build, or a task's setup failed. | Contact your platform operator (template or host problem), or check the task. |
| 405 method_not_allowed | DrumsError (status 405) | Only on the MCP endpoint (/mcp): it takes POST and DELETE, and was called with another method. On /v1 routes an unsupported method is 404. | Point an MCP client at the endpoint; do not open it in a browser or with GET. |
| 429 rate_limited | Overloaded | More than 20 requests/s per key (burst 60), or too many failed authentications from your IP address. | Wait Retry-After seconds and slow down. |
| 429 overloaded | Overloaded | The host has no capacity right now (desktops, memory, or room for saved states). Nothing was started. | Retry after Retry-After seconds, or close computers you no longer need. |
| 502 bad_gateway | GuestError | The desktop's guest server did not answer. | Retry the step once; if it repeats, reset or close the computer. |
| 503 retryable_infrastructure_failure | DaemonUnavailable | The runtime or the gateway's database did not answer. For a create or fork whose reply was lost, the gateway adopts or closes what was made. | Retry GETs (the SDK does, for retry_s). For a POST, list your computers before retrying. |
In Python
The SDK raises a subclass of drums.DrumsError chosen by HTTP status and refined by code. Every exception has status, message and body (the parsed reply):
Python
import drums
with drums.connect() as client:
try:
client.create(image="no-such-image")
except drums.NotFound as e:
print(e.status, e.body["code"], e.body["request_id"][:3])
env = client.create(ttl=600)
env.close()
try:
env.step("pyautogui.moveTo(1, 1)")
except drums.EnvGone as e:
print("gone:", e.status, e.body["code"])| HTTP status | Exception |
|---|---|
| 400 | BadRequest |
| 401 | AuthError |
| 404 | NotFound |
| 409 | Conflict |
| 410 | EnvGone |
| 422 | BadRequest |
| 429 | Overloaded |
| 502 | GuestError |
| 503 | DaemonUnavailable |
Errors that are not HTTP replies:
| Exception | When |
|---|---|
DaemonUnavailable (status 0) | No reply: network down, or the server kept answering 503 for retry_s. For a POST the outcome is unknown: check with env.refresh() or client.envs() |
ActionFailed | step(): the action ran and exited non-zero (check=False returns it instead) |
RestoreFailed, GateFailed, TaskSetupFailed | create(), reset() or a fork child came back not ready; the computer exists on the server until closed |
InvalidEpisode, CheckerError | verify(strict=True): the episode is not valid, or the checker failed |
ForkError, BatchError | Part of a fork or a create_many failed; .ok holds what worked |
Retrying
| Situation | Retry? |
|---|---|
429 rate_limited, 429 overloaded | Yes, after Retry-After. Nothing was started |
| 503 on a GET | Yes (the SDK does it for you, up to retry_s) |
| 503 on a POST, or no reply | Not blindly: the gateway may have made the computer or fork. List your computers first; the gateway closes any desktop it made but could not report |
403 quota_exceeded / budget_exceeded | Not until you free capacity or the limit changes |
409 not_quiescent | Yes; nothing was captured |
410 env_gone | No: create a new computer |
400, 401, 403 forbidden, 404, 422 | No: fix the request, key or task |