[BUG] [Claude Desktop / Linux] Cowork & Dispatch hang on infinite spinner — app opens its own storage directories with O_DIRECT, ext4 returns EINVAL

Status Open
Reported on v2.1.246
Maintainer reply None cached
Activity 2 comments · opened Aug 28, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

This is the Claude Desktop application (claude-desktop 1.37937.3, arm64, installed
from Anthropic's apt repo), NOT the Claude Code CLI.

The Cowork / Dispatch tab in Claude Desktop shows a loading spinner indefinitely and
never becomes usable. No error message is ever displayed. Restarting the app does not
help. The tab spins forever with no timeout and no error state.

Root cause: the app opens its own storage directories under ~/.config/Claude with the
O_DIRECT flag. O_DIRECT on a directory is invalid on ext4, so the kernel returns EINVAL,
and every write path under ~/.config/Claude fails.

strace shows the exact call:

openat(AT_FDCWD, "/home/pi/.config/Claude/vm_bundles/claudevm.bundle",
O_RDONLY|O_DIRECT|O_LARGEFILE|O_CLOEXEC) = -1 EINVAL (Invalid argument)

The same call with the same flags and the same errno fails on:
~/.config/Claude/vm_bundles/claudevm.bundle
~/.config/Claude/claude-code/2.1.246
~/.config/Claude/claude-code-sessions/<org>/<uuid>
~/.config/Claude/local-agent-mode-sessions/<org>/<uuid>
~/.config/Claude/local-agent-mode-sessions/<org>/<uuid>/rpm
~/.config/Claude/local-agent-mode-sessions/<org>/<uuid>/agent/local_ditto_<uuid>/outputs
~/.config/Claude/local-agent-mode-sessions/skills-plugin/<uuid>/<org>/skills

All of these are ordinary directories (drwx------ pi:pi). Confirmed on the same path:
python3: os.open(dir, O_RDONLY|O_DIRECT) -> EINVAL [Errno 22] Invalid argument
python3: os.open(dir, O_RDONLY) -> ok
python3: os.open(dir, O_RDONLY|O_DIRECTORY) + fsync -> ok
node: fs.promises.open(dir, 'r') -> ok

Call sites visible in main.log: ensureStorageDir / writeSessionToDisk,
_syncPlugins, ensurePluginStructure, primeSessionDirs, CCD downloader.

The failure cascades: the stale rootfs.img cannot be refreshed, the Claude Code SDK
2.1.246 download fails 3/3 attempts, session initialisation fails, QEMU is therefore
never spawned (pgrep -a qemu is empty while the app is running), and the UI shows a
spinner forever because the session it is waiting on never initialises.

This is NOT a missing-requirement problem. KVM, vhost_vsock, QEMU and the kvm group
are all correctly set up and the app never reports any of the documented
"Cowork requires ..." messages. See Environment below.

Cowork worked correctly on this machine until 2026-08-28 08:59 (clean VM shutdown in
the logs). It broke on the 09:04 restart, when the app first requested a new
rootfs.img version and could not write it.

I searched existing issues for "O_DIRECT" and "EINVAL" and found no report of this.
Related but not duplicates: #35116 (VM download fails because destination dir can't be
written, Windows/ENOENT), #37925 (Linux downloader failure), #24070 (requests that guest
console output be logged on failure — my kernel-console.log is 29 bytes and empty).

What Should Happen?

  1. The app should not pass O_DIRECT when opening directories. O_DIRECT is meaningless

on a directory and is rejected with EINVAL by ext4 (and other filesystems). A plain
open, or O_DIRECTORY where a directory handle is wanted, works correctly here.

  1. Cowork / Dispatch should start normally: VM bundle refreshes, SDK installs, QEMU

launches, session initialises.

  1. If startup does fail, the UI should surface an actionable error rather than an

indefinite spinner. The Cowork tab already has error states for missing QEMU, missing
KVM and missing vhost_vsock; a total storage failure like this should surface one too,
with a timeout rather than spinning forever.

Error Messages/Logs

--- strace (openat calls returning EINVAL) ---
openat(AT_FDCWD, ".../Claude/local-agent-mode-sessions/<org>/<uuid>/rpm", O_RDONLY|O_DIRECT|O_LARGEFILE|O_CLOEXEC) = -1 EINVAL (Invalid argument)
openat(AT_FDCWD, ".../Claude/vm_bundles/claudevm.bundle",                 O_RDONLY|O_DIRECT|O_LARGEFILE|O_CLOEXEC) = -1 EINVAL (Invalid argument)
openat(AT_FDCWD, ".../Claude/claude-code/2.1.246",                        O_RDONLY|O_DIRECT|O_LARGEFILE|O_CLOEXEC) = -1 EINVAL (Invalid argument)
openat(AT_FDCWD, ".../Claude/claude-code-sessions/<org>/<uuid>",          O_RDONLY|O_DIRECT|O_LARGEFILE|O_CLOEXEC) = -1 EINVAL (Invalid argument)
openat(AT_FDCWD, ".../Claude/local-agent-mode-sessions/skills-plugin/<uuid>/<org>/skills", O_RDONLY|O_DIRECT|O_LARGEFILE|O_CLOEXEC) = -1 EINVAL (Invalid argument)

--- cowork_vm_node.log ---
[Bundle:status] rootfs.img version mismatch: have=6d1538ba…, want=2a762adf…
[setYukonSilverConfig] Stale bundle present; refreshing in background
[setYukonSilverConfig] Stale-bundle refresh failed (non-fatal): EINVAL: invalid argument, open '/home/pi/.config/Claude/vm_bundles/claudevm.bundle'
[linux-vm] Spawning helper: /usr/lib/claude-desktop/resources/cowork-linux-helper
[cowork-linux-helper] [server] listening on /run/user/1000/claude-cowork-vm.sock
[error] [download] VM download failed: EINVAL: invalid argument, open '/home/pi/.config/Claude/vm_bundles/claudevm.bundle'

(last successful run, before the break:)
[VM:shutdown] App quit, stopping VM … [vm] qemu exited: <nil> … Completed in 3644ms

--- main.log ---
[error] [CCD] Download attempt 1/3 failed Error: EINVAL: invalid argument, open '/home/pi/.config/Claude/claude-code/2.1.246'
[error] [CCD] Download attempt 2/3 failed …
[error] [CCD] Download attempt 3/3 failed …
[error] [CCD] All download attempts failed
[error] Failed to save session local_<uuid>: EINVAL: invalid argument, open '.../claude-code-sessions/<org>/<uuid>'
    at async open (node:internal/fs/promises:640:25)
    at async e.ensureStorageDir (…/index2.chunk-CknQXpFk.js)
    at async e.writeSessionToDisk (…/index2.chunk-CknQXpFk.js)
[error] [LocalPlugins] Failed to sync remote plugins: EINVAL … /rpm
[warn]  [SkillsPlugin] Periodic sync failed: EINVAL … /skills
[error] [audit] logger init failed — dropping entries { error: "EINVAL … /agent/local_ditto_<uuid>" }
[error] Session

Steps to Reproduce

  1. Install Claude Desktop 1.37937.3 (arm64) from Anthropic's apt repository on

Debian 13 (trixie), with ~/.config on an ext4 filesystem.

  1. Sign in and use Cowork/Dispatch successfully (worked here until 2026-08-28 08:59).
  2. Restart the app after the server-side rootfs.img version changes, so the app has to

refresh a stale VM bundle.

  1. Open the Cowork / Dispatch tab.
  2. Observe: spinner forever, no error shown. pgrep -a qemu is empty while the app runs.
  3. Confirm the cause directly — this reproduces standalone, no app needed:

python3 -c "import os,sys; d=os.path.expanduser('~/.config/Claude'); os.open(d, os.O_RDONLY|os.O_DIRECT)"
-> OSError: [Errno 22] Invalid argument
while a plain open of the same directory succeeds.

  1. Or capture it from the app:

strace -f -y -e trace=openat -o /tmp/claude-strace.log claude-desktop
grep EINVAL /tmp/claude-strace.log | grep '\.config/Claude'

Claude Model

_No response_

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.215

Platform

Other

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Other

Additional Information

Product: Claude Desktop app (Linux beta) — not the Claude Code CLI
Version: claude-desktop 1.37937.3, arm64 (apt: downloads.claude.ai stable)
OS: Debian GNU/Linux 13 (trixie)
Kernel: 6.18.34+rpt-rpi-2712, aarch64, page size 16384 (Raspberry Pi 5, 16 GB)
Filesystem: ext4 on NVMe, rw, noatime, 146 GB free, 8% inodes, no I/O errors in dmesg
Virtualisation: /dev/kvm and /dev/vhost-vsock both present; user in kvm group;
vhost_vsock loaded; qemu-system-arm, qemu-efi-aarch64, virtiofsd installed;
qemu-system-aarch64 -accel help lists kvm; systemd-detect-virt = none

The target directory is created but left empty:
~/.config/Claude/claude-code/2.1.215 250M (working, previously installed)
~/.config/Claude/claude-code/2.1.246 4.0K (empty, created 2026-08-28 09:04)
The app successfully creates the directory, then fails on the subsequent
O_DIRECT open of that same directory, so no SDK content is ever written.

View original on GitHub ↗

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