[BUG] preview_screenshot silently hangs the session when Preview server is not found — error is logged but never returned to tool caller
[BUG] preview_screenshot silently hangs the session when Preview server is not found — error is logged but never returned to the tool caller
Summary
When preview_screenshot is called with a serverId that no longer exists (evicted, idle-killed, or belonging to a different concurrent session), the internal PreviewError is logged as [warn] in main.log but never propagated back to the MCP tool caller. The Claude session hangs indefinitely on the spinner with no error, no timeout, and no recovery path.
---
Reproduction
- Open 2+ Claude Code sessions simultaneously, each working on a web project with Claude Preview active.
- In any session, trigger
preview_screenshotafter the preview server has been idle or after a Claude Desktop restart. - Expected: tool returns an error — e.g.
{"error": "Preview not found for server <id>"}— and the session continues. - Actual: session freezes indefinitely. No error shown. Spinner never resolves.
Reliably reproducible with parallel sessions or after the IdleManager:preview evicts a server (1800s timeout).
---
Evidence — logs from ~/.config/Claude/logs/main.log
Preview server spawned and marked ready:
2026-05-07 20:41:45 [info] [Preview] Starting server with config
2026-05-07 20:41:45 [info] [Preview] Process spawned { pid: 60693 }
2026-05-07 20:41:49 [info] [Preview] Server ready (HTTP responding) { serverId: '95c45eea-105f-4253-b737-52d6c014e1b2' }
Same session, 31 minutes later — screenshot fails silently:
2026-05-07 21:13:24 [warn] [Preview] capturePreviewScreenshot failed: {
error: TO [PreviewError]: Preview not found for server b50c9380-9bbd-4025-898a-ba1597eae9b2
at Object.capturePreviewScreenshot (.../app.asar/.vite/build/index.js:1264:17074)
[message]: 'Preview not found for server b50c9380-9bbd-4025-898a-ba1597eae9b2',
name: 'PreviewError'
The error recurs across days and multiple server IDs — this is not a one-off:
2026-05-06 23:17:18 [warn] [Preview] capturePreviewScreenshot failed: Preview not found for server ba4f127d-dcbf-4d83-a295-b5a62a4e8d45
2026-05-06 23:22:01 [warn] [Preview] capturePreviewScreenshot failed: Preview not found for server ba4f127d-dcbf-4d83-a295-b5a62a4e8d45
2026-05-06 23:23:43 [warn] [Preview] capturePreviewScreenshot failed: Preview not found for server ba4f127d-dcbf-4d83-a295-b5a62a4e8d45
2026-05-07 13:19:28 [warn] [Preview] capturePreviewScreenshot failed: Preview not found for server ba4f127d-dcbf-4d83-a295-b5a62a4e8d45
2026-05-07 19:24:30 [warn] [Preview] capturePreviewScreenshot failed: Preview not found for server b50c9380-9bbd-4025-898a-ba1597eae9b2
2026-05-07 20:07:29 [warn] [Preview] capturePreviewScreenshot failed: Preview not found for server b50c9380-9bbd-4025-898a-ba1597eae9b2
2026-05-07 21:13:24 [warn] [Preview] capturePreviewScreenshot failed: Preview not found for server b50c9380-9bbd-4025-898a-ba1597eae9b2
Note: b50c9380 is a different serverID than 95c45eea (the one spawned for that session at 20:41:49). This indicates Claude is sometimes calling preview_screenshot with a stale serverID from a previous or concurrent session — and getting no feedback when it fails.
---
Root cause
capturePreviewScreenshot throws a PreviewError when the serverID is not in the active registry. The error is caught and logged at [warn] level, but the MCP tool response is never sent back to the calling Claude session. The tool call is left open, blocking the session's tool-use pipeline indefinitely.
This is consistent with the behavior described in #57134 (retry-budget exhaustion causing silent hangs) — the same pattern of "error is known internally but never surfaced to the session."
---
Impact
- Every session that calls
preview_screenshotafter an idle eviction or with a stale serverID is permanently frozen. - With 2+ parallel sessions, stale serverID cross-contamination is common — both sessions seen frozen in under 1 hour of normal use (today's session: 20:28 and 21:08 hang timestamps).
- No user-facing recovery: Escape does not unblock the tool call. Session must be closed and restarted, losing context.
---
Proposed fix
In the capturePreviewScreenshot handler, catch PreviewError and return it as a structured MCP tool error instead of logging and silently dropping it:
- } catch (e) {
- logger.warn('[Preview] capturePreviewScreenshot failed:', { error: e });
- }
+ } catch (e) {
+ logger.warn('[Preview] capturePreviewScreenshot failed:', { error: e });
+ return { isError: true, content: [{ type: 'text', text: e.message }] };
+ }
This single change would let Claude recover gracefully — it would see the error, understand the preview server is gone, and could call preview_start to respawn it rather than hanging forever.
---
Environment
- Claude Desktop 0.10.x / Claude Code 2.1.64
- Linux (Fedora 43, kernel 6.19)
- Multiple concurrent Claude Code sessions (3–5) on Max 20x plan
- Preview idle timeout: 1800s (
IdleManager:preview)
Related
- #57134 — client-side silent hang pattern (same failure mode, different trigger)
- #53922 — concurrent session rate-limiting (parallel context)
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗