Cowork mode hangs in renderer JS loop after force-quit during agent task

Resolved 💬 3 comments Opened May 10, 2026 by Blumps47 Closed Jun 8, 2026

main-process-sample.txt
main-ui-renderer-sample.txt
renderer-stack-sample.txt

Bug: Cowork mode hangs in renderer JS loop after force-quit during agent task

Environment

  • Claude Code Desktop v1.6608.2
  • macOS 26.1 (Darwin 25.1.0) on Apple Silicon
  • Max plan

Trigger

Disk filled to 95% during an active Cowork agent task. Force-quit the app to free space. Cowork has been unusable since.

Symptom

  • Cowork mode hangs at "Authenticating..." spinner
  • UI becomes unclickable; eventually macOS pinwheel forces another force-quit
  • Chat mode works fine

Diagnostic data (from sample of renderer PID during hang)

The hang is purely in the renderer's main thread JavaScript. No network I/O involved.

Chrome_ChildIOThread is parked at kevent64 for all 2427 samples. Completely idle. No HTTP/websocket activity.

com.apple.main-thread shows three concurrent patterns:

  1. Recursive dynamic ES module imports:

``
node::PrincipalRealm::host_import_module_dynamically_callback (depth 5+)
-> v8::ValueSerializer::WriteValue
-> host_import_module_dynamically_callback (recurses)
``

  1. Cascading Promise rejections:

``
v8::Promise::Resolver::Reject -> Reject -> Reject -> Reject (5+ levels)
``

  1. Regex re-evaluation loop:

``
v8::RegExp::GetFlags repeated 19+ times in a tail-recursive chain
``

Combined signature

The renderer dynamically imports a module, runs a regex on the resolved value, the regex (or its match handler) rejects a Promise, the catch handler re-imports the module, loop forever. All errors silently swallowed in JS, which explains why main.log stops emitting after [oauth] obtained new token / [warn] Transcript not found for session local_X (cliSessionId: none).

Reproduces every time

A fresh orphan session directory is created on every Cowork attempt at:

~/Library/Application Support/Claude/local-agent-mode-sessions/<accountId>/<orgId>/local_X/

Contents:

  • .audit-key (51 bytes)
  • audit.jsonl (containing the user prompt)
  • outputs/ (empty)

The expected sibling local_X.json metadata file is never written, because the renderer enters the loop before metadata write.

Already ruled out as causes

  • Disk space (recovered to 30 GB free)
  • VM bundle (deleted; rebuilt cleanly; vsock connects, IPv4 routing healthy, coworkd ready)
  • OAuth (re-authenticated via fresh OAuth flow; chat works; logs show [oauth] obtained new token, caching succeeding)
  • Local session orphans (cleared; recreated on each launch anyway)
  • Plugins (~/.claude/plugins/ - disabled, no change)
  • Skills (~/.claude/skills/ - disabled, no change)
  • MCP servers (config emptied, no change)
  • Local Storage / IndexedDB / Session Storage (cleared, no change)
  • Tailscale connectivity (verified working)

Repro steps

  1. Have a Cowork task in flight
  2. Force-quit Claude.app (or Activity Monitor -> Force Quit)
  3. Relaunch -> open Cowork tab, attempt new or existing task
  4. Hang every time

Workaround

Use Chat mode only. For agent capability, use the Claude Code CLI directly (claude in terminal or VS Code extension) - both bypass the broken Cowork renderer path entirely.

Attached diagnostic files

  • renderer-stack-sample.txt - PID 88959 (Cowork sidepanel renderer, 5.9% CPU during hang)
  • main-ui-renderer-sample.txt - PID 88903 (main UI renderer, 16.8% CPU during hang)
  • main-process-sample.txt - PID 88883 (Electron main process)

The renderer-stack-sample is the most informative - the hang signature is in there.

Hypothesis on the fix

The catch block in the cowork session-load path needs to either:

  1. Stop retrying (break the recursion when error count > N)
  2. Surface the error to the user instead of silently swallowing
  3. Both

The dynamic-import target that fails should also be investigated for whether it's expecting state that was cleared by the force-quit.

View original on GitHub ↗

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