macOS: Read of an image >~200KB deadlocks every subsequent API call (surfaces as ECONNRESET after retry ladder); session permanently poisoned incl. --resume
Summary
On macOS (arm64, macOS 26.3), when the built-in Read tool ingests an image whose raw size is above ~200KB (base64 ~256KiB), the next API request never completes: the CLI silently retries for ~5.5 minutes (the full 10-step ladder), then reports API Error: Unable to connect to API (ECONNRESET) and exits 1. The image block persists in the session transcript, so every subsequent call — including any --resume of that session — fails identically. In our case a headless daemon that resumes one long-lived session was down for 17 hours from a single 411KB image.
The server is not involved: the identical payload succeeds instantly via curl from the same machine, both auth paths.
One-command repro (macOS)
Any JPEG/PNG ≥ ~210KB:
printf '%s' 'Use the Read tool on /tmp/big.jpg then output one word.' | claude -p --model claude-haiku-4-5-20251001 --allowedTools "Read"
# hangs silently ~5.5 min → "API Error: Unable to connect to API (ECONNRESET)", exit 1
Isolation matrix (all on the same machine/token unless noted)
| Probe | Result |
|---|---|
| image ≤166KB raw (128/512/768/896px variants) | works |
| image ≥206KB raw (1024px, 206KB) | fails |
| threshold bracket | fail cliff between 166KB and 206KB raw ≈ [221KiB, 275KiB] base64 — consistent with a 256KiB constant |
| model | fails on both claude-opus-4-5-20251101 and claude-haiku-4-5-20251001 |
| CLI version | fails on 2.1.225 and 2.1.226 (native builds) |
| auth | fails with subscription OAuth and ANTHROPIC_API_KEY |
| sandbox | fails with sandbox enabled and {"sandbox":{"enabled":false}} |
| fresh session vs resumed | fails in a fresh session (not a big-context issue; session was 3 messages) |
| 600KB compressible text via Read | works |
| 300KB incompressible (base64 noise) text via Read | works — rules out wire-size / compression theories; trigger is image content blocks specifically |
| same 206KB image via curl to /v1/messages, IPv4, API key | HTTP 200 in 0.9s |
| same image via curl, IPv6 | 200 in 0.9s |
| same image via curl with subscription bearer + anthropic-beta: oauth-2025-04-20 | 200 in 1.3s |
| same image, same CLI version, Linux | works |
Process state during the hang (sample on macOS)
- The process accumulates 8+ ESTABLISHED TCP connections to
api.anthropic.com:443(one per retry; none ever completes a request; no data flowing). - A bundled native module (
.99cedbef9bde5bbb-0.node, Rust symbols, plustokio-rt-workerthreads and anHTTP Clientthread) shows threads parked in_pthread_cond_wait/__psynch_cvwaitthroughout the hang — consistent with a deadlock in a native image-handling or dispatch path rather than a network failure. Fullsampleoutput available on request.
Why this is worse than a failed call
The oversized image is written into the session JSONL before the failure, so the session is permanently poisoned: every later turn and every --resume inherits it (same shape as #8202/#26126, but with a transport-level symptom no HTTP status ever reaches). The 2.1.126 self-healing ("oversized images in history are automatically removed and the request retried") does not fire — this image violates no documented limit (1408×768, 411KB, valid JPEG), and the failure never surfaces as a 4xx.
Suggested fixes
- Find/fix the macOS-specific deadlock on large image blocks (the
cond_waitstacks in the bundled native module during dispatch are the lead). - Extend the 2.1.126 auto-strip to trigger on repeated transport-level failures of a request containing image blocks — after N identical resets, drop the newest image and retry, so one bad image can't strand a session (critical for headless/daemon usage).
Readshould derivemedia_typefrom magic bytes, not extension (#13396) — related hygiene in the same path (our trigger file was JPEG bytes named.png).
Environment
- Claude Code 2.1.225 and 2.1.226 (native install), macOS 26.3 (25D125), arm64 (Mac Mini)
- Reproduced headless (
-p) with--allowedTools Read; unaffected Linux control: CLI 2.1.227 on x86_64
Related: #51164, #56140, #8202, #26126, #13396, #30124
🤖 Filed with Claude Code after a joint human/Claude root-cause session.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗