How to Read Cowork Daemon Logs and Troubleshoot Startup Failures in Claude Desktop

To diagnose Cowork startup failures in Claude Desktop, examine the daemon lifecycle log at ~/.config/Claude/logs/cowork_vm_daemon.log and use grep to isolate startup, exit, and error events—the missing or final log entry reveals whether the daemon failed to fork, crashed during initialization, or was killed by the system.

The aaddrick/claude-desktop-debian repository packages Claude Desktop for Linux systems, including the Cowork VM daemon (cowork-vm-service.js) that hosts the isolated VM for Cowork mode. When the Electron front-end cannot establish a connection, the daemon's own logs provide the definitive diagnostic record. This guide explains how to locate these logs, interpret the lifecycle events, and resolve the most common Linux-specific startup blockers.

Understanding the Cowork Daemon Architecture

The Cowork daemon follows a strict initialization sequence that is instrumented with lifecycle logging. Understanding this sequence helps you read the logs effectively.

Auto-Launch Mechanism

The Electron client triggers daemon startup through an injection in build.sh (Patch 6). When the Unix-domain socket at $XDG_RUNTIME_DIR/cowork-vm-service.sock is missing, the client calls child_process.fork() with detached:true, redirecting the child’s stdio to the log file. To prevent fork bombs during crash loops, a cooldown guard (FUNC._lastSpawn) rate-limits restart attempts.

Lifecycle Logging Infrastructure

Inside scripts/cowork-vm-service.js, the logLifecycle() function writes unconditional entries for critical events: startup, listening, SIGTERM, SIGINT, and uncaughtException. This ensures that even silent crashes or external kills leave a trace in the log file.

Socket Creation Sequence

The daemon emits a lifecycle startup … line immediately upon invocation. After initializing the VM environment, it creates the Unix socket and writes lifecycle listening …. If the log shows startup but never reaches listening, the daemon crashed during VM initialization—typically due to bubblewrap namespace restrictions or corrupted bundle files.

Locating and Reading the Daemon Logs

Primary Log File Location

The daemon writes its lifecycle log to a fixed path under your home directory:


~/.config/Claude/logs/cowork_vm_daemon.log

This path is defined in the logging implementation within scripts/cowork-vm-service.js (source line 5). The client-side launcher logs complementary auto-launch events to ~/.cache/claude-desktop-debian/launcher.log, which shows [cowork-autolaunch] messages when the fork is attempted.

Real-Time Log Monitoring

To watch the daemon startup in real time, stream the log file using tail:

tail -f ~/.config/Claude/logs/cowork_vm_daemon.log

Then attempt to start a Cowork session from the Claude Desktop interface. The log will update live as the daemon initializes, listens, or crashes.

Key Lifecycle Events to Grep For

Isolate the most diagnostic entries by filtering for lifecycle events:

grep -E 'lifecycle (startup|exit|SIGTERM|SIGINT|uncaughtException|unhandledRejection)' \
    ~/.config/Claude/logs/cowork_vm_daemon.log | tail -20

Missing startup indicates the client never successfully forked the daemon. startup without listening indicates a crash during initialization. uncaughtException reveals Node-level errors, often from corrupted VM bundles.

Common Startup Failure Patterns

Symptom (Client) Log Pattern Likely Cause Fix / Investigation
"Starting VM…" hangs, reconnect loop No startup line, or only startup then nothing Fork failed (fork() didn’t complete) – usually a permission or AppArmor issue. Check launcher.log for [cowork-autolaunch] errors. Ensure the daemon can create its log directory; verify AppArmor profile permits the fork.
bwrap is installed but cannot create a user namespace bwrap is installed but cannot create a user namespace in cowork_vm_daemon.log (documented in TROUBLESHOOTING.md) Ubuntu 24.04+ ships with apparmor_restrict_unprivileged_userns=1, blocking bubblewrap’s userns. Install a permissive AppArmor profile for /usr/bin/bwrap (see "Permit user namespaces" block in docs/TROUBLESHOOTING.md).
SIGKILL / OOM lifecycle startup … then a gap, no further entries The daemon was killed externally (OOM killer, kill -9). Look at dmesg or system logs for OOM events; increase memory or limit other processes.
uncaughtException lifecycle uncaughtException … line with stack trace Node-level bug, often caused by corrupted bundle files. Remove the offending bundle directory (~/.config/Claude/vm_bundles/claudevm.bundle/), then restart.
Preserved image files prevent startup No startup entry at all after a fresh launch sessiondata.img or rootfs.img.zst left from a previous broken install blocks daemon initialization (see "Secondary cause" in daemon learnings). Delete the bundle directory mentioned above or let the auto-reinstall code clean those files (Patch 6b adds them to the delete list).

Step-by-Step Diagnostic Commands

Run these commands in sequence to isolate the root cause of a Cowork startup failure:


# 1. Verify the daemon process (if any)

pgrep -af cowork-vm-service

# 2. Verify the socket exists

ls -la "${XDG_RUNTIME_DIR:-/tmp}/cowork-vm-service.sock"

# 3. Stream the daemon lifecycle log (real-time)

tail -f ~/.config/Claude/logs/cowork_vm_daemon.log

# 4. Inspect recent key events (startup, exit, signals)

grep -E 'lifecycle (startup|exit|SIGTERM|SIGINT|uncaughtException|unhandledRejection)' \
    ~/.config/Claude/logs/cowork_vm_daemon.log | tail -20

# 5. Look for orphan sockets (helpful if the client hangs)

lsof -U 2>/dev/null | grep -iE 'cowork|claude'

# 6. Force a respawn test – kill the daemon and watch the client reconnect

pkill -9 -f cowork-vm-service.js
tail -f ~/.cache/claude-desktop-debian/launcher.log   # watch for [cowork-autolaunch] messages

# 7. If bubblewrap user-ns is blocked (Ubuntu 24.04+)

sudo tee /etc/apparmor.d/bwrap <<'EOF'
abi <abi/4.0>,
include <tunables/global>

profile bwrap /usr/bin/bwrap flags=(unconfined) {
    userns,
    include if exists <local/bwrap>
}
EOF
sudo apparmor_parser -r /etc/apparmor.d/bwrap

All commands are safe, read-only operations except the sudo block, which modifies the local system’s AppArmor policy as described in the official troubleshooting documentation.

Summary

  • The Cowork daemon writes a detailed lifecycle log to ~/.config/Claude/logs/cowork_vm_daemon.log.
  • Missing or incomplete log entries pinpoint whether the daemon never started, was killed, or crashed.
  • Common Linux-specific roadblocks are bubblewrap user-namespace restrictions (fixed with an AppArmor profile) and stale VM bundle images (fix by deleting ~/.config/Claude/vm_bundles/claudevm.bundle/).
  • Use the diagnostic commands above to inspect the process, socket, and log; then apply the appropriate remediation from the failure patterns table.

Following this workflow lets you quickly locate and resolve most Cowork startup failures without needing to rebuild the whole application.

Frequently Asked Questions

Where exactly does the Cowork daemon write its logs?

The daemon writes its lifecycle log to ~/.config/Claude/logs/cowork_vm_daemon.log. This path is hardcoded in the logLifecycle() function within scripts/cowork-vm-service.js. The client-side launcher writes complementary auto-launch messages to ~/.cache/claude-desktop-debian/launcher.log.

Why does the log show "startup" but never "listening"?

When you see a lifecycle startup entry without a subsequent lifecycle listening entry, the daemon initialized but crashed during VM setup before creating the Unix socket. This typically indicates a bubblewrap user-namespace restriction on Ubuntu 24.04+ or corrupted VM bundle files in ~/.config/Claude/vm_bundles/claudevm.bundle/.

How do I fix the "bwrap cannot create a user namespace" error?

Ubuntu 24.04 and newer restrict unprivileged user namespaces by default. Create a permissive AppArmor profile for bubblewrap by writing the configuration to /etc/apparmor.d/bwrap with the userns permission flag, then reload the profile with sudo apparmor_parser -r /etc/apparmor.d/bwrap. This allows the daemon to create the isolated environment required for Cowork mode.

What should I delete if the daemon keeps crashing on startup?

If the log shows uncaughtException or the daemon fails to start entirely, delete the VM bundle directory at ~/.config/Claude/vm_bundles/claudevm.bundle/. This directory contains sessiondata.img and rootfs.img.zst files that may be corrupted or locked from a previous failed session. The daemon will re-extract these files on the next launch.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →