cloudflare / cloudflare/containers
Containers local dev on WSL2 (kernel 6.18.x): app container never created, only egress proxy-everything sidecar; 'Container failed to start'
- Dominant language
- TypeScript
- Stars
- 270
- Forks
- 42
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 4
Description
## Summary
Running a `@cloudflare/sandbox` container in **local dev on WSL2 (kernel 6.18.x)** never starts the container. Miniflare/workerd builds the image and starts the egress `cloudflare/proxy-everything` sidecar, but the **actual app container is never created**. The readiness probe to the container aborts and workerd throws `kj/timer.c++:30: overloaded: operation timed out`, surfacing as **`Container failed to start`**. Deployed/remote containers are unaffected — this is local-dev only.
## Expected vs actual
- **Expected:** `getSandbox(env.SANDBOX, id).exec("echo hi")` starts the container and returns.
- **Actual:** the call hangs ~100s; the DO retries; only a `workerd----proxy` container exists in `docker ps` — the app container (`cloudflare-dev/:`) is never created. Fails with `Container failed to start`.
## Dev-server output
```
{ level: 'info', message: 'Using http transport', component: 'sandbox-do', ... }
Error checking if container is ready: The operation was aborted (x4)
e = kj/timer.c++:30: overloaded: operation timed out
; sentryErrorContext = jsgInternalError; wdErrId = ...
{ level: 'error', message: 'Sandbox error', error: { message: 'Container failed to start' } }
{ level: 'warn', message: 'container.startup', outcome: 'unrecognized_error', error: 'Container failed to start' }
{ level: 'info', message: 'Container not ready, retrying', status: 503, attempt: N }
```
## Minimal reproduction
`wrangler.jsonc`
```jsonc
{
"name": "sbx-repro",
"main": "src/index.ts",
"compatibility_date": "2026-07-01",
"containers": [{ "class_name": "Sandbox", "image": "./Dockerfile", "instance_type": "basic", "max_instances": 1 }],
"durable_objects": { "bindings": [{ "name": "SANDBOX", "class_name": "Sandbox" }] },
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["Sandbox"] }]
}
```
`Dockerfile`
```dockerfile
FROM docker.io/cloudflare/sandbox:0.12.3
```
`src/index.ts`
```ts
import { getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(_req: Request, env: { SANDBOX: DurableObjectNamespace }) {
const sandbox = getSandbox(env.SANDBOX, "repro");
const result = await sandbox.exec("echo hi");
return Response.json(result);
},
};
```
1. On WSL2 with a **6.18.x** kernel and native `docker-ce` (containerd image store), run the dev server (`@cloudflare/vite-plugin` `pnpm dev`, or `wrangler dev`).
2. `curl http://127.0.0.1:/`.
3. Request hangs, then `Container failed to start`. `docker ps` shows only the `...-proxy` sidecar, never the app container.
## Key evidence (failure is workerd/miniflare-side, not the image or Docker)
- **The built image runs fine standalone:** `docker run --rm cloudflare-dev/:` boots and the container-server listens on `:3000`.
- **Docker daemon logs (`journalctl -u docker`)** during a run show **only** the `-proxy` endpoint joining the bridge (recreated in a ~30s loop). There is **no create/start** for the app-image container — the create never reaches the daemon.
- Host→container **TCP and HTTP** on `:3000` = `200` in ~2ms; `docker0` (172.17.0.1) present and bindable. Networking to a manually-run container is fine.
- The only thing the app-container create does that a plain `docker run` and the proxy create do **not** is wire the container into the egress proxy's network — that step appears to be where it hangs.
## What was ruled out
- **Toolchain version** — reproduced on both `workerd 1.20260521.1` and the newest `workerd 1.20260701.1`.
- **The image / disk / BuildKit** — image builds (`docker build` rc=0) and runs standalone; isolated builds succeed.
- **`enableInternet`** — a `Sandbox extends Base { enableInternet = false }` subclass does **not** help; the `proxy-everything` sidecar is created for every local container regardless (see workers-sdk#14242).
- **Docker Desktop** — not in use; native `docker-ce`, active context `default`. A stale `desktop-linux` context was removed with no change.
- **BuildKit `only one connection allowed` session warnings** — temporally disjoint from the container-start attempts; not related.
## Hypothesis
An environment regression in the **local-dev container↔egress-proxy networking** path (miniflare/workerd) on **WSL2 kernel 6.18.x**. The container image, Docker, and host↔container networking all work in isolation; only workerd's app-container create (with proxy network wiring) fails. It is not fixed by upgrading the toolchain or by app-level config.
## Environment
| | |
|---|---|
| OS | WSL2 (Ubuntu), kernel **`6.18.33.2-microsoft-standard-WSL2`** (built 2026-06-18), WSL `2.7.10.0` |
| Docker | native **docker-ce 29.6.1** (not Docker Desktop); **containerd image store** (`overlayfs` / `io.containerd.snapshotter.v1`) |
| `@cloudflare/sandbox` | `0.12.3` (also `0.10.3`) |
| `@cloudflare/containers` | `0.3.7` (also `0.3.5`) |
| `@cloudflare/vite-plugin` | `1.43.0` (also `1.38.0`) |
| `wrangler` | `4.107.0` (also `4.94.0`) |
| `miniflare` | `4.20260701.0` (also `4.20260521.0`) |
| `workerd` | `1.20260701.1` (also `1.20260521.1`) |
| Node | `22.x` |
## Possibly related
- cloudflare/containers#155 — local-dev container monitor lifecycle / `cloudflare-dev/*` image-tagging race.
- cloudflare/workers-sdk#14242 — `proxy-everything` egress sidecar behavior in local dev.
Contributor guide
Research direction
Reproduce with the wrangler.jsonc, Dockerfile, and src/index.ts example using wrangler dev or pnpm dev, then inspect the local-dev app-container creation and egress-proxy network-wiring path in miniflare/workerd. Done means the app container is created alongside the proxy sidecar and getSandbox(...).exec("echo hi") returns instead of timing out.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, linux, typescript
- Domain
- devtools, infrastructure, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100