Skip to content

Instantly share code, notes, and snippets.

@Koubek
Last active July 17, 2026 10:38
Show Gist options
  • Select an option

  • Save Koubek/d3a8158085b087f981e767643206ec86 to your computer and use it in GitHub Desktop.

Select an option

Save Koubek/d3a8158085b087f981e767643206ec86 to your computer and use it in GitHub Desktop.
Recover Docker Sandboxes (sbx) on Windows without losing sandbox memory — daemon-down recovery, single-sandbox shim/pipe failures, auto-start, and safe cleanup.

Docker Sandboxes (sbx) on Windows — Recovery Runbook

Two failures this covers — identify yours first:

What you see Which section
Every sbx command fails: "daemon not reachable" / sbx diagnose shows Daemon=fail Symptom A (daemon down)
Daemon is fine, most sandboxes work, but one sandbox won't start: failed to start shim … shim exited before creating pipe: exit status 1 Symptom B (zombie shim / pipe collision)

Golden rules: Your sandbox data lives on disk in containerd — a daemon restart or an OS reboot never loses it. Never run sbx reset to troubleshoot; it wipes every sandbox and isn't needed for either failure below.

Tested on: Windows 11, sbx v0.35.0.


Symptom A — "daemon not reachable" (daemon isn't running)

sbx diagnose shows:

Daemon    fail   not reachable
          detail: open \\.\pipe\docker_kaname_sandboxd: The system cannot find the file specified.
          hint:   Run: sbx daemon start

Fix (memory-safe, ~10s)

sbx daemon start -d      # -d = DETACHED. This is the important part.
sbx daemon status        # expect: Status: running
sbx ls                   # all sandboxes should be listed = memory intact

⚠️ The #1 gotcha

sbx daemon start without -d runs in the FOREGROUND and never returns — it looks like a hang. If you Ctrl+C it, you kill the daemon and you're back to square one.

  • ✅ Always use sbx daemon start -d.
  • ✅ If a start seems stuck, open a second terminal, run sbx daemon status; if running, leave the first alone.
  • ❌ Don't Ctrl+C a foreground daemon.

Make it automatic (start daemon at logon)

$sbx = "$env:LOCALAPPDATA\DockerSandboxes\bin\sbx.exe"
$action    = New-ScheduledTaskAction -Execute $sbx -Argument 'daemon start -d'
$trigger   = New-ScheduledTaskTrigger -AtLogOn -User "$env:USERDOMAIN\$env:USERNAME"
$principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -LogonType Interactive -RunLevel Limited
$settings  = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit ([TimeSpan]::Zero) -Hidden
Register-ScheduledTask -TaskName 'DockerSandboxes-sbx-daemon' -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description 'Starts the sandboxd daemon detached at user logon.' -Force

Remove with: Unregister-ScheduledTask -TaskName 'DockerSandboxes-sbx-daemon' -Confirm:$false


Symptom B — one sandbox won't start (others work)

Client error:

ERROR: failed to start sandbox: start runtime: 500 Internal Server Error: failed to start runtime

Daemon log (…\sandboxes\state\sandboxd\daemon.log):

creating containerd task for container <id>: failed to start shim:
  io.containerd.nerdbox.v1: shim exited before creating pipe: exit status 1

Cause

A zombie containerd-shim-nerdbox-v1.exe process, left over from a previous unclean daemon death (e.g. the daemon was Ctrl+C'd — see Symptom A), is stuck in the kernel and keeps its named pipe \\.\pipe\containerd-shim-<id> pinned. The affected sandbox deterministically reuses that same pipe id for its new shim, can't bind it, and the shim aborts before it can create its stdio pipe. Sandboxes with different shim ids are unaffected — which is why only one (or a couple) fail while the rest work.

Diagnose

# 1) Look for old-dated zombie shims (StartTime days ago, often huge CPU):
Get-Process containerd-shim-nerdbox-v1 | Select-Object Id, StartTime, CPU

# 2) See the pinned pipes:
[System.IO.Directory]::GetFiles('\\.\pipe\') | Where-Object { $_ -match 'containerd-shim' }

# 3) (Optional) confirm the collision — restart the daemon with shim debug, then start the sandbox:
sbx daemon stop
$env:SANDBOXD_LOG_LEVEL = 'debug'; sbx daemon start -d
#   ...retry the sandbox, then look in daemon.log for the shim line:
#   "using pipe path from environment pipe=\\.\pipe\containerd-shim-<id>"
#   ...restore normal logging afterwards:
sbx daemon stop; Remove-Item Env:\SANDBOXD_LOG_LEVEL; sbx daemon start -d

The zombie is un-killable: taskkill /F /PID"There is no running instance of the task"; WMI Terminate → access-denied. Its parent process is already gone; it's pinned by a lingering kernel handle.

What does NOT fix it (don't waste time / risk on these)

  • ❌ Killing the process (Stop-Process / taskkill / WMI Terminate)
  • wsl --shutdown
  • ❌ Restarting the Host Compute Service (Restart-Service vmcompute) — verified no effect, and it disrupts WSL/containers
  • ❌ Restarting the sbx daemon

Fix: reboot the machine

A kernel-pinned zombie is only released by a full OS reboot. It's completely memory-safe (reboot ≠ sbx reset; all sandbox data persists on disk). After reboot, the logon task starts the daemon automatically:

sbx daemon status                 # should already be running
sbx run --name <the-sandbox>      # starts cleanly now

Where your data lives (so you know what's safe)

Root: %LOCALAPPDATA%\DockerSandboxes\

Path What it is Safe to touch?
sandboxes\state\sandboxd\containerd\root\ Persistent container store (meta.db, snapshots) = your sandbox memory ❌ Never delete
sandboxes\state\sandboxd\containerd\state\…\io.containerd.runtime.v2.task\ Ephemeral per-task runtime state ⚠️ Advanced only (below)
sandboxes\data\ analytics only (not sandbox memory)
sandboxes\logs\ logs

Advanced: surgical state cleanup (only if a daemon start truly wedges on reconnect)

Back up rather than delete; never touch …\containerd\root\:

sbx daemon stop
$task = "$env:LOCALAPPDATA\DockerSandboxes\sandboxes\state\sandboxd\containerd\state\io.containerd.runtime.v2.task"
Rename-Item "$task\docker" "docker.bak"
sbx daemon start -d
sbx ls

Diagnostics (for bug reports)

sbx diagnose               # local checks
sbx diagnose --upload      # returns a diagnostics id to share

Related

GitHub docker/sbx-releases#272 — a genuine shim-creation failure on Linux/macOS (failed to create shim task: ttrpc: closed). That's a different bug from either symptom here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment