Use this symptom-to-fix map. For deeper recovery, refer to Errors and recovery. For lifecycle behavior, refer to Sandbox lifecycle.
| Symptom | What to check |
|---|---|
RuntimeControlProtocolError, control/protocol failures after deploy |
Worker package and container image are on different lines. Use the same @next / cloudflare/sandbox:next (or the same exact prerelease) pair. |
Container never becomes ready, or you see repeated ContainerUnavailableError |
Cold start or capacity. Back off using retryAfterMs when set, then retry the work. Refer to Errors and recovery. |
Works in wrangler dev, fails in production only |
Production-only limits and cold start. Still keep package/image matched. |
| Symptom | What to check |
|---|---|
await exec “finished” but the command did not |
exec resolves on launch. Use output(), waitForExit(), or exitCode. |
| No stdout as a string | output() defaults to bytes. Pass { encoding: "utf8" }. |
getProcess is null / list is [] |
No container running, or ID unknown in the current container. Discovery does not wake a sandbox. Relaunch from stored job state if needed. |
StaleProcessHandleError |
Handle was from a previous container. Start a new exec from checkpointed work. |
| Wait timed out / aborted but process still runs | Local wait only. Call kill() if you intend to stop it. |
| Port never becomes ready | Default waitForPort mode is TCP. Use mode: "http" for HTTP checks. Process may have exited — check status/logs. |
| Need interactive stdin | Not on the process handle. Use a terminal or non-interactive argv/cwd/env. |
| Symptom | What to check |
|---|---|
Browser still uses sessionId |
Preview xterm helper expects terminalId. |
getTerminal is null |
Same lifetime rules as processes. Create again if the container was replaced. |
| Reconnect has no history | Pass the last cursor into connect / output options. |
| Symptom | What to check |
|---|---|
Env from an earlier exec “disappeared” |
No session shell. Use setEnvVars and/or per-launch env. Environment variables. |
| API keys leaked into the container | Do not put live secrets in sandbox env. Use outbound traffic handlers on the Worker. |
| Symptom | What to check |
|---|---|
sandbox.createCodeContext is not a function |
Attach withInterpreter and call sandbox.interpreter.*. |
| Python not available | Use the -python image variant on the same @next line. |
| Symptom | What to check |
|---|---|
Bridge /exec, sessions, or /pty behavior differs from @next Worker SDK docs |
The self-deployed bridge is not part of the 1.0 preview. Use the stable bridge with matching stable package and container image. |
For agents and long-running tools on @next:
- Launch with
exec(argv)(often['/bin/bash', '-lc', script]). - Wait with
waitForLog,waitForPort, orlogs— not onlyawait exec. - Persist job state (command,
cwd,env, checkpoint), not onlyprocess.id. - On a later request:
getProcess(id)while the same container may still hold it; otherwiseexecagain. - Use a terminal only when you need a human PTY, not as a session substitute.
Refer to Process execution, Migrate, and examples in the sandbox-sdk ↗ repo (claude-code, codex, opencode, and others).