Skip to content

Environment lifecycle

The task-environment state machine — how a `POST /environments` advances from build → provision → ready, and how clients observe it.

POST /environments returns immediately with state="building" and an id. The platform provisions the task sandbox asynchronously; clients poll GET /environments/{id}/status until the state is terminal. The synchronous behavior — HTTP holding open for the full provision — was retired because it broke under fan-out (the CapabilityEnvAdapter pattern) and tripped client-side timeouts on cold image pulls.

Terminal window
dn env create security-mutillidae-sqli-login-bypass --wait
# state=building # fast initial response
# state=provisioning
# state=ready # service_urls + execute_token populated

The execute_token is delivered in the POST /environments 201 response and never appears in subsequent polls — the server only stores its hash. Stash it on receipt; you cannot recover it from GET /environments/{id} or /status.

StateMeaningservice_urlsexecute_token (in POST response)error
buildingTask image isn’t cached; SandboxBuildsWorker is compiling it.nullpopulatednull
provisioningBuild is ready; the provider is bringing the sandbox up.nullpopulatednull
readySandbox is reachable. Run execute, read instructions, drive the agent.populatedpopulatednull
pausedSandbox is suspended (cost-saving, user action).populatedn/a (delivered earlier)null
torn_downSandbox is terminated. Final state after DELETE.nulln/a (delivered earlier)null
failedBuild or provision failed. Inspect error and retry.nulln/a (delivered earlier)populated

Transitions are monotonic with one exception: paused → ready when a paused sandbox resumes. Everything else flows forward.

GET /environments/{id}/status is the cheap polling endpoint — returns just the state snapshot. GET /environments/{id} returns the full resource with the same state-aware fields.

Terminal window
dn env status <env-id> --json
# {"id": "...", "state": "provisioning", "expires_at": null, "service_urls": null}

The SDK (dn.task_env(...) / TaskEnvironment.setup()) and the CLI (dn env create --wait) both poll transparently with exponential backoff (1s → 5s cap). Client-side deadline is the caller’s timeout_sec when set, else 15 minutes. A failed state raises RuntimeError with the server-provided error.

Peak concurrent task sandboxes for a CapabilityEnvAdapter run is concurrency × parallel_rows (candidates in parallel × dataset rows scored concurrently per candidate). The async POST /environments is what makes this composable — each provision returns quickly and the SDK handles the polling in the background, so a fan-out of 10 concurrent provisions doesn’t saturate the HTTP connection pool.

SymptomWhere to look
state="failed" with error: "task build failed: ..."Task image didn’t compile. Inspect dn task info <ref> or the task’s build logs.
state="failed" with error: "BadGatewayError: ..."Provider rejected the sandbox (resource limits, image missing architecture). Check the host Docker daemon or E2B provider.
state stuck in building past deadlineThe API pod that owned the provision crashed mid-flight. Reprovision; the original env id is no longer recoverable.
execute_token missingThe token is only returned in the POST /environments 201 response — polls never carry it. Stash it on receipt; if you lost it, DELETE and reprovision.