Repository navigation
WSL2: restart-policy containers start before the WSL bind-mount proxy is ready (file mounts fail with "not a directory", directory mounts are empty) #731
Description
Bug description
On a cold start of Docker Desktop (WSL2 backend), dockerd starts containers that have restart: unless-stopped before the WSL integration proxy (docker-desktop-user-distro proxy) has populated /mnt/wsl/docker-desktop-bind-mounts/<distro>/. Every container with a bind mount from the integrated distro is affected:
- Single-file bind mount: the container does not start.
Exited (127), andState.Erroris:failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/run/desktop/mnt/host/wsl/docker-desktop-bind-mounts/Ubuntu/<hash>" to rootfs at "/etc/clickhouse-server/config.d/load.xml": ... not a directory: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected typeRestartCountstays0: the restart policy never retries, because the task was never created. The container stays down until it is started manually. - Directory bind mount: the container starts and even reports
healthy, but the mount target is an empty directory. In our case nginx returned 404 from an empty/var/www, and two consumers saw an empty data directory. This silent variant is worse than the hard failure.
docker restart <container> fixes both without any config change. The source files and directories in the distro are intact the whole time.
Whether the WSL distro is cold or warm decides the outcome. Running Docker Desktop as administrator makes no difference (tested both ways):
- After
wsl --shutdown, the first Docker Desktop start always breaks. - Quitting Docker Desktop and starting it again while the distro is still running always works.
Environment
- Windows 10.0.26300.9550
- WSL 3.0.1.0, kernel 6.18.40.1
- Docker Desktop 4.94.0 (241994), Engine 29.8.2, WSL2 backend
- Integrated distro: Ubuntu 26.04.1 LTS with
[boot] systemd=truein/etc/wsl.conf - Compose projects live in the distro filesystem (
/home/<user>/...), and their services userestart: unless-stopped
Timeline from the logs
Sources: %LOCALAPPDATA%\Docker\log\host\com.docker.backend.exe.log* and %LOCALAPPDATA%\Docker\log\vm\init.log*.
- Proxy mounted: the first
docker-desktop-user-distro.apiproxy ... mounting /home/... to /mnt/wsl/docker-desktop-bind-mounts/Ubuntu/<hash>line. - First container start: the first
not a directoryerror, or, when nothing failed, the earliestState.StartedAtamong bind-mounted containers.
| Start (UTC) | WSL state | First container start | Proxy mounted | Result |
|---|---|---|---|---|
| 20:00:54 | cold (after wsl --shutdown) |
20:01:00.440 | 20:01:01.995 | proxy 1.55 s late, failures |
| 20:02:29 | cold | 20:02:34.414 | 20:02:36.335 | proxy 1.92 s late, failures |
| 20:03:48 | cold | 20:03:53.299 | 20:03:54.489 | proxy 1.19 s late, failures |
| 19:56:24 | warm (Desktop quit and started again) | 19:56:27.091 | 19:56:26.804 | proxy 0.29 s ahead, OK |
| 20:04:11 | warm | 20:04:14.442 | 20:04:14.127 | proxy 0.31 s ahead, OK |
Overall: 5 of 5 cold starts failed and 4 of 4 warm starts succeeded that evening. On the warm starts the proxy wins by only ~0.3 s, so every start is a race.
On a cold start the extra time goes to the distro boot:
start wsl integration for distro Ubuntuis logged ~3 s afterstarting engine linux/wsl, vs ~1.2 s on a warm start.- The first
wsl.exe -d Ubuntu -e cat /etc/wsl.conftakes 2.1 s (distro boot with systemd), vs ~0.1 s on a warm start. - Whatever the integration state, dockerd starts restart-policy containers ~5 s after
starting engine linux/wsl.
Reproduction steps
- In the integrated WSL distro (in its own filesystem, not under
/mnt/c), create a project:mkdir -p ~/bind-race/data && cd ~/bind-race echo hello > app.conf touch data/file.txt
compose.yaml:services: file-mount: image: alpine:3.22 restart: unless-stopped command: ["sh", "-c", "cat /config/app.conf && sleep infinity"] volumes: - ./app.conf:/config/app.conf:ro dir-mount: image: alpine:3.22 restart: unless-stopped command: ["sh", "-c", "ls -A /data && sleep infinity"] volumes: - ./data:/data:ro
- Run
docker compose up -dand check that both containers are running and thatdocker compose exec dir-mount ls -A /datashowsfile.txt. - Quit Docker Desktop from the tray, then run
wsl --shutdownin PowerShell. - Start Docker Desktop. Do not open the distro beforehand.
- Check the containers:
file-mountisExited (127), anddocker inspect -f '{{.State.Error}}' bind-race-file-mount-1shows thenot a directoryerror.dir-mountisUp, butdocker compose exec dir-mount ls -A /datais empty.
- Quit Docker Desktop and start it again without
wsl --shutdown. Both containers now come up correctly.
Expected behavior
At engine startup, containers whose bind sources come from an integrated WSL distro should not be started until the integration proxy for that distro is ready. Alternatively, Docker Desktop could retry a failed restart-policy start once the proxy is ready.
Workaround
After Docker Desktop is up, restart every container that has a bind mount from the distro (docker restart ... or docker compose up -d --force-recreate).
Related
#601 (same symptoms after a Windows reboot, open since 2024) and #176 (same not a directory error with unless-stopped). This report adds the timing evidence and the cold-vs-warm determinism.
Поле: Platform
Windows
Client:
Version: 29.8.2
API version: 1.56
Go version: go1.26.8
Git commit: 7fc2dff
Built: Wed Sep 30 19:31:45 2026
OS/Arch: linux/amd64
Context: default
Server: Docker Desktop 4.94.0 (241994)
Engine:
Version: 29.8.2
API version: 1.56 (minimum version 1.40)
Go version: go1.26.8
Git commit: 8af9fe3
Built: Wed Sep 30 19:32:25 2026
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v2.3.6
GitCommit: ee2735368117d2eb259779949d5e75cdafec9761
runc:
Version: 1.5.1
GitCommit: v1.5.1-0-g8f2685a4
docker-init:
Version: 0.19.0
GitCommit: de40ad0
Client:
Version: 29.8.2
Context: default
Debug Mode: false
Plugins:
agent: Docker AI Agent Runner (Docker Inc.)
Version: v1.144.0
Path: /usr/local/lib/docker/cli-plugins/docker-agent
ai: Docker AI Agent - Ask Gordon (Docker Inc.)
Version: v1.31.0
Path: /usr/local/lib/docker/cli-plugins/docker-ai
buildx: Docker Buildx (Docker Inc.)
Version: v0.37.2
Path: /usr/local/lib/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v5.5.1
Path: /usr/local/lib/docker/cli-plugins/docker-compose
debug: Get a shell into any image or container (Docker Inc.)
Version: 0.0.47
Path: /usr/local/lib/docker/cli-plugins/docker-debug
desktop: Docker Desktop commands (Docker Inc.)
Version: v0.4.4
Path: /usr/local/lib/docker/cli-plugins/docker-desktop
dhi: CLI for managing Docker Hardened Images (Docker Inc.)
Version: v0.0.7
Path: /usr/local/lib/docker/cli-plugins/docker-dhi
extension: Manages Docker extensions (Docker Inc.)
Version: v0.2.31
Path: /usr/local/lib/docker/cli-plugins/docker-extension
init: Creates Docker-related starter files for your project (Docker Inc.)
Version: v1.4.0
Path: /usr/local/lib/docker/cli-plugins/docker-init
mcp: Docker MCP Plugin (Docker Inc.)
Version: v0.44.1
Path: /usr/local/lib/docker/cli-plugins/docker-mcp
model: Docker Model Runner (Docker Inc.)
Version: v1.2.6
Path: /usr/local/lib/docker/cli-plugins/docker-model
offload: Docker Offload (Docker Inc.)
Version: v0.6.53
Path: /usr/local/lib/docker/cli-plugins/docker-offload
pass: Docker Pass Secrets Manager Plugin (beta) (Docker Inc.)
Version: v0.2.4
Path: /usr/local/lib/docker/cli-plugins/docker-pass
sandbox: "docker sandbox" is deprecated, use Docker Sandboxes instead (Docker Inc.)
Version: v0.13.0
Path: /usr/local/lib/docker/cli-plugins/docker-sandbox
scout: Docker Scout (Docker Inc.)
Version: v1.25.0
Path: /usr/local/lib/docker/cli-plugins/docker-scout
Server:
Containers: 36
Running: 26
Paused: 0
Stopped: 10
Images: 44
Server Version: 29.8.2
Storage Driver: overlayfs
driver-type: io.containerd.snapshotter.v1
Logging Driver: local
Cgroup Driver: cgroupfs
Cgroup Version: 2
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
CDI spec directories:
/etc/cdi
/var/run/cdi
Discovered Devices:
cdi: docker.com/gpu=webgpu
Swarm: inactive
Runtimes: io.containerd.runc.v2 nvidia runc
Default Runtime: runc
Init Binary: docker-init
containerd version: ee2735368117d2eb259779949d5e75cdafec9761
runc version: v1.5.1-0-g8f2685a4
init version: de40ad0
Security Options:
seccomp
Profile: builtin
cgroupns
Kernel Version: 6.18.40.1-microsoft-standard-WSL2
Operating System: Docker Desktop (containerized)
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 15.18GiB
Name: docker-desktop
ID: <redacted>
Docker Root Dir: /var/lib/docker
Debug Mode: false
HTTP Proxy: http.docker.internal:3128
HTTPS Proxy: http.docker.internal:3128
No Proxy: hubproxy.docker.internal
Labels:
com.docker.desktop.address=unix:///var/run/docker-cli.sock
Experimental: false
Insecure Registries:
hubproxy.docker.internal:5555
127.0.0.0/8
::1/128
Live Restore Enabled: false
Firewall Backend: iptables
Activity
[-]Контейнеры с restart policy стартуют раньше, чем готов прокси для монтирования из WSL.[/-][+]WSL2: restart-policy containers start before the WSL bind-mount proxy is ready (file mounts fail with "not a directory", directory mounts are empty)[/+]