Initializing Enclave...

How to Fix Docker Desktop Stuck 'Is Stopping' Forever on Windows WSL2 Backend Crash

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 5–15 mins


TL;DR

  • What broke: The docker-desktop WSL2 distro process (wslhost.exe / vmmemWSL) crashed or deadlocked, leaving Docker Desktop's shutdown sequence waiting on a response that will never come.
  • How to fix it: Force-kill the orphaned WSL and Docker processes via PowerShell, terminate the hung WSL distro, then issue a full wsl --shutdown before restarting Docker Desktop.
  • Fast path: Use our Client-Side Sandbox below to auto-refactor this — paste your %APPDATA%\Docker\log\host\docker-desktop.log output and get a targeted fix without sending data to any server.

The Incident (What Does the Error Mean?)

Docker Desktop transitions to a stopping state and never exits it. The UI spinner runs indefinitely. Task Manager shows Docker Desktop.exe, com.docker.backend.exe, and wslhost.exe all still resident in memory.

Raw symptom in %APPDATA%\Docker\log\host\docker-desktop.log:

[2024-xx-xx T xx:xx:xx] Starting shutdown sequence
[2024-xx-xx T xx:xx:xx] Waiting for com.docker.backend to exit...
[2024-xx-xx T xx:xx:xx] Sending shutdown signal to WSL distro 'docker-desktop'
[2024-xx-xx T xx:xx:xx] Timeout waiting for WSL distro to stop (30000ms elapsed)
[2024-xx-xx T xx:xx:xx] WSL distro 'docker-desktop-data' still running

Immediate consequence: Docker Desktop is completely non-functional. You cannot restart it — clicking the icon spawns a second instance that detects the first is still "running" and aborts. All containers are inaccessible. Port bindings remain held by the dead process.


The Attack Vector / Blast Radius

This is a cascading process deadlock, not a clean crash. The WSL2 backend (docker-desktop distro) relies on a Hyper-V socket (hvsock) channel to communicate shutdown acknowledgment back to the Windows-side com.docker.backend.exe. When the Linux init process inside the distro hangs — due to OOM inside the WSL VM, a corrupted ext4.vhdx, a bad kernel module, or a Windows host sleep/hibernate cycle interrupting the Hyper-V socket — that acknowledgment never arrives.

Blast radius:

  • wslhost.exe holds the virtual disk (ext4.vhdx) file lock — you cannot compact, copy, or repair the disk while it is running.
  • Any CI pipeline using a local Docker context (GitHub Actions self-hosted runner, Jenkins agent) is completely blocked.
  • Named pipe //./pipe/docker_engine remains bound — any docker CLI call returns error during connect: ... The system cannot find the file specified. or hangs indefinitely.
  • On laptops: this state survives a Windows user logout. The processes are session-0 elevated; a normal restart is the only guaranteed clean exit — unless you follow the steps below.

How to Fix It (The Solution)

Basic Fix — Force Kill and WSL Reset

Run the following in an elevated PowerShell (Run as Administrator):

- # DO NOT do this — closing Docker Desktop UI does nothing in this state
- # DO NOT do this — End Task on Docker Desktop.exe alone leaves wslhost.exe orphaned
- Stop-Process -Name "Docker Desktop" -Force

+ # Step 1: Kill all Docker-related processes in correct dependency order
+ $dockerProcs = @("docker", "dockerd", "com.docker.backend", "com.docker.build", "Docker Desktop")
+ foreach ($p in $dockerProcs) {
+     Get-Process -Name $p -ErrorAction SilentlyContinue | Stop-Process -Force
+ }
+
+ # Step 2: Terminate the hung WSL host process
+ Get-Process -Name "wslhost" -ErrorAction SilentlyContinue | Stop-Process -Force
+ Get-Process -Name "vmmemWSL" -ErrorAction SilentlyContinue | Stop-Process -Force
+
+ # Step 3: Full WSL subsystem shutdown (terminates ALL distros cleanly at kernel level)
+ wsl --shutdown
+
+ # Step 4: Verify no docker-desktop distro is still registered as running
+ wsl --list --verbose
+
+ # Step 5: Wait 5 seconds, then restart Docker Desktop normally
+ Start-Sleep -Seconds 5
+ Start-Process "$env:ProgramFiles\Docker\Docker\Docker Desktop.exe"

Confirm WSL distro is stopped before restarting. wsl --list --verbose must show docker-desktop and docker-desktop-data both in Stopped state.


Enterprise Best Practice — Prevent the Hang at the Source

The root causes are well-known. Address them at the infrastructure level:

1. WSL2 Memory Limit (prevents OOM-induced hangs)

- # No .wslconfig exists — WSL2 consumes up to 50% of host RAM by default
- # On a 16GB machine this is 8GB — enough to OOM-kill the Docker init process

+ # File: C:\Users\<YourUser>\.wslconfig
+ [wsl2]
+ memory=4GB
+ processors=4
+ swap=2GB
+ swapFile=%USERPROFILE%\AppData\Local\Temp\wsl-swap.vhdx
+ pageReporting=true
+ kernelCommandLine=vsyscall=emulate

2. Disable Fast Startup (the #1 cause of hvsock corruption after sleep)

- # Windows Fast Startup enabled (default) — hybridizes shutdown with hibernate
- # Hyper-V sockets from previous session are NOT cleanly torn down
- # Result: wslhost.exe reconnects to a stale socket handle on resume

+ # Run in elevated PowerShell — disables Fast Startup permanently
+ powercfg /hibernate off
+ # Additionally in: Control Panel > Power Options > Choose what the power buttons do
+ # Uncheck: "Turn on fast startup (recommended)"

3. Automate recovery with a watchdog script (for self-hosted CI runners)

- # No monitoring — runner just hangs, build times out after 6 hours

+ # docker-watchdog.ps1 — run as a Scheduled Task every 5 minutes
+ $backend = Get-Process "com.docker.backend" -ErrorAction SilentlyContinue
+ $wsl = (wsl --list --verbose) -match "docker-desktop"
+ if (-not $backend -and $wsl -match "Running") {
+     Write-EventLog -LogName Application -Source "DockerWatchdog" \
+         -EventId 9001 -EntryType Warning \
+         -Message "Docker backend dead but WSL distro running. Forcing reset."
+     wsl --shutdown
+     Start-Sleep -Seconds 8
+     Start-Process "$env:ProgramFiles\Docker\Docker\Docker Desktop.exe"
+ }

💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

For self-hosted GitHub Actions / Jenkins runners on Windows:

  1. Pre-job health check step — add this as the first step in every pipeline job:
- name: Assert Docker is healthy
  shell: powershell
  run: |
    $result = docker info 2>&1
    if ($LASTEXITCODE -ne 0) {
      Write-Error "Docker not healthy: $result"
      exit 1
    }
  1. Runner pre-flight script — register a Windows Scheduled Task that runs wsl --shutdown on every system resume event (Event ID 107, Kernel-Power):
$trigger = New-ScheduledTaskTrigger -AtStartup
$action = New-ScheduledTaskAction -Execute "wsl.exe" -Argument "--shutdown"
Register-ScheduledTask -TaskName "WSL-Resume-Reset" -Trigger $trigger -Action $action -RunLevel Highest -Force
  1. VHDX integrity check in weekly maintenance window:
# Compact and check the virtual disk — run while Docker Desktop is fully stopped
Optimize-VHD -Path "$env:LOCALAPPDATA\Docker\wsl\data\ext4.vhdx" -Mode Full
  1. Pin Docker Desktop version in enterprise fleet using Winget or Chocolatey with a tested, known-stable version. WSL2 backend regressions are common across minor Docker Desktop releases:
# Lock to a specific version via winget
winget install Docker.DockerDesktop --version 4.28.0 --override "--quiet"
  1. Monitor with Windows Event Log — the HCS (Host Compute Service) provider logs WSL2 VM lifecycle events. Alert on Event ID 304 (VM termination unexpected) in the Microsoft-Windows-Hyper-V-Worker log channel.

Related Diagnostics

"Part of the Performance Utility Matrix."

View all 219 Performance Tools →