Claude Desktop: cowork VM gvisor auto-recovery causes cascading boot failures requiring full VM reinstall

Resolved 💬 2 comments Opened Feb 11, 2026 by gwicho38 Closed Mar 12, 2026

Bug Description

Claude Desktop's cowork VM has an auto-recovery mechanism that switches networking from vmnet (via "auto" mode) to gvisor when it detects an API reachability failure. This creates a cascading failure that ultimately requires deleting the entire VM bundle:

  1. The gvisor switch is persisted to config.json, causing subsequent VM startups to fail at vsock connect
  2. Repeated failed boots and force-kills corrupt the VM image, so even after restoring vmnet networking and resetting EFI state, the guest kernel no longer boots at all
  3. The only fix is deleting the entire VM bundle and letting the app re-download from scratch (~10 GB)

Environment

  • App version: 1.1.2685
  • Platform: macOS 26.2.0 (Darwin 25.2.0), Apple M4 Pro, arm64
  • Network mode before failure: auto (vmnet, working perfectly)
  • Network mode after failure: gvisor (VM boots at hypervisor level but guest never connects via vsock)

Root Cause Analysis

Phase 1: gvisor auto-recovery breaks networking

On Feb 9, a momentary API reachability failure triggered the auto-recovery code:

// Triggered by Go.on("apiReachability", ...) when status === "UNREACHABLE"
if (Qr && _w() !== "gvisor") {
  vq("gvisor");  // permanently persists to config.json
  // restarts VM in gvisor mode
}

This permanently set "coworkNetworkMode": "gvisor" in config.json. All subsequent boots used gvisor and failed at guest_vsock_connect with 60-second timeouts.

Phase 2: Repeated force-kills corrupt the VM

Each failed boot attempt follows this pattern:

  1. VM boots at hypervisor level (vm_boot completed)
  2. Guest never connects via vsock (60s timeout)
  3. VM is force-stopped: "Timeout waiting for VM to stop (state: 1), proceeding with cleanup"

After 5+ force-kills across Feb 10-11, the VM became permanently broken. The guest kernel no longer produces any output at all:

  • coworkd.log not updated (guest daemon never starts)
  • console_tail: undefined (no console output from hvc0)
  • kernel_console_tail: undefined (no kernel boot messages from hvc1)

Phase 3: Neither config fix nor EFI reset resolves it

We attempted the following fixes in order — none worked:

  1. Restored "coworkNetworkMode": "auto" — vmnet networking was established correctly (bridge100 up at 192.168.64.1), but guest still didn't boot
  2. Deleted efivars.fd to reset EFI/GRUB state — fresh EFI vars were created on next boot, but guest kernel still produced zero output
  3. Deleted entire VM bundle (~/Library/Application Support/Claude/vm_bundles/claudevm.bundle/) — this was the only fix, forcing a fresh ~10 GB download

Why the rootfs corruption isn't detected

The app skips on-disk integrity checks for the rootfs:

[VM:integrity] Rootfs is compressed — checksum is for compressed form, skipping on-disk integrity check

The checksum was only validated against the compressed .zst file during the original download. After repeated force-kills corrupted the on-disk image, there was no mechanism to detect or repair it.

Timeline

| Date | Time | Mode | Result |
|------|------|------|--------|
| Feb 5 | 13:48 | auto (vmnet) | Boot in 13.6s |
| Feb 9 | 15:40 | auto (vmnet) | Boot successful |
| Feb 9 | 15:41 | gvisor (auto-switched) | Boot OK this one time |
| Feb 10 | 13:23 | gvisor | Last successful coworkd activity |
| Feb 10 | 18:45 | gvisor | Timeout — force killed |
| Feb 10 | 18:59 | gvisor | Timeout — force killed |
| Feb 11 | 10:09 | gvisor | Timeout — force killed |
| Feb 11 | 10:11 | gvisor | Timeout — force killed |
| Feb 11 | 10:13 | gvisor | Timeout — force killed |
| Feb 11 | 10:22 | auto (vmnet, config fixed) | Timeout — guest kernel dead |
| Feb 11 | 10:27 | auto (vmnet, efivars deleted) | Timeout — guest kernel still dead |
| Feb 11 | 10:29 | — | Deleted entire VM bundle |

Workaround

Delete the entire VM bundle and relaunch Claude Desktop:

rm -rf ~/Library/Application\ Support/Claude/vm_bundles/claudevm.bundle/

Also ensure the network mode is reset:

# In ~/Library/Application Support/Claude/config.json
# Change "coworkNetworkMode": "gvisor" to "coworkNetworkMode": "auto"

The app will re-download the rootfs (~10 GB) and create fresh VM state on next launch.

Suggested Fixes

For the gvisor auto-recovery:

  1. Don't persist gvisor as the default — use it as a one-time fallback, not a permanent config change
  2. Add retry logic — if gvisor fails N times, revert to auto
  3. Allow explicit vmnet mode — the config validator only accepts "auto" or "gvisor"
  4. Surface the change to users — show a notification when the network mode is automatically changed

For VM corruption prevention:

  1. Validate rootfs on disk — store and check the uncompressed checksum, not just the compressed one
  2. Graceful VM shutdown — avoid force-killing the VM when vsock connect times out
  3. Auto-reset on repeated failures — after N consecutive boot failures with no console output, automatically delete and re-download the rootfs
  4. Limit force-kill retries — don't keep rebooting a VM that's clearly broken

Log Files

Relevant logs are in:

  • ~/Library/Logs/Claude/cowork_vm_swift.log — Virtualization.framework events
  • ~/Library/Logs/Claude/cowork_vm_node.log — Node.js VM orchestration
  • ~/Library/Logs/Claude/coworkd.log — Guest daemon (no entries after corruption)
  • ~/Library/Logs/Claude/main.log — Electron app events

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗