Cowork mode hangs in renderer JS loop after force-quit during agent task
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:
- Recursive dynamic ES module imports:
````
node::PrincipalRealm::host_import_module_dynamically_callback (depth 5+)
-> v8::ValueSerializer::WriteValue
-> host_import_module_dynamically_callback (recurses)
- Cascading Promise rejections:
````
v8::Promise::Resolver::Reject -> Reject -> Reject -> Reject (5+ levels)
- 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,
coworkdready) - OAuth (re-authenticated via fresh OAuth flow; chat works; logs show
[oauth] obtained new token, cachingsucceeding) - 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
- Have a Cowork task in flight
- Force-quit Claude.app (or Activity Monitor -> Force Quit)
- Relaunch -> open Cowork tab, attempt new or existing task
- 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:
- Stop retrying (break the recursion when error count > N)
- Surface the error to the user instead of silently swallowing
- Both
The dynamic-import target that fails should also be investigated for whether it's expecting state that was cleared by the force-quit.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗