Skip to content

Imaged payloads above ~20 MiB fail unpredictably, and /compact cannot escape (no image-byte budget) #157

Description

@byingyang

Summary

Imaged requests become unreliable once the rendered wire payload passes roughly 20 MiB.
Below that line, success is essentially 100%.
Above it, requests fail as 500, 502, empty 200 (status 200 with no usage/tokens and no usable content), or stall for up to 5 minutes.

pxpipe applies no upper bound on rendered image bytes, so a long session drifts into this zone on its own.
The part that turns this from "occasional retry" into "stuck session" is that /compact cannot escape it, because compaction sends the same oversized history through the same compression path.

Evidence

From my own ~/.pxpipe/events.jsonl, 10,257 imaged requests over 2026-07-10 to 2026-07-28, models claude-opus-5 and claude-fable-5.
"ok" means status 200 with a non-zero input token count.

rendered payload n ok fail success rate
0-8 MiB 7965 7943 22 99.7%
8-14 MiB 1074 1056 18 98.3%
14-18 MiB 683 658 25 96.3%
18-19.5 MiB 257 257 0 100.0%
19.5-20 MiB 84 84 0 100.0%
20-21 MiB 119 96 23 80.7%
21-24 MiB 77 50 27 64.9%

341 consecutive requests between 18 and 20 MiB succeeded without a single failure, so the degradation onset is sharp and sits right around 20 MiB.

Failure modes above 19.5 MiB:

model outcome n payload range
claude-opus-5 500 8 20.08 MiB
claude-opus-5 empty 200 8 20.08 MiB
claude-fable-5 502 19 20.25-21.20 MiB
claude-fable-5 empty 200 11 20.26-21.85 MiB
claude-fable-5 500 3 21.85 MiB
claude-fable-5 stall, 120s-317s 11 20+ MiB

This is a reliability cliff, not a hard cap.
claude-fable-5 has 202 successes in the 19.74-21.64 MiB range, including a clean 200 at 21.64 MiB with 315 images.
So requests above 20 MiB are sometimes served and sometimes not.

The mix of 502, empty 200, and multi-minute stalls points at an upstream edge or gateway behavior on large request bodies rather than a model-level limit.
I want to be explicit about the limit of my evidence here: I have not captured an upstream error body.
pxpipe discards 5xx bodies unless PXPIPE_DEBUG_CAPTURE_4XX=1, so the classification above is inferred from status, timing, and size, not from the server's own error text.

Why this is invisible until it breaks

The Claude Code context meter is a token measure, and compression is doing its job on tokens.
The failure is a byte measure on the wire.
Those move in opposite directions, so there is no warning signal.

In the session where I hit this, the meter showed 32% of a 1M context window while the rendered payload on the wire was 20.08 MiB and every request was failing.
Nothing surfaced in the dashboard indicated that wire bytes were the problem.

The actual blocker: compaction deadlock

Once a session is above the line, the normal remedy is /compact.
That fails too, with the same signature:

Error during compaction: API Error: 500 Internal server error.

Compaction has to send the history it is trying to summarize, that history is what exceeds 20 MiB, and it goes through compression like any other request.
So the session has no in-band way out.
That is the part I would prioritize.

Workaround that recovered the session

  1. Disable compression for the model (dashboard chip / global toggle), keeping the same model.
  2. Run /compact, which now goes as plain text and succeeds.
  3. Re-enable compression and continue.

The session survived with no model switch and no context loss.
It does require knowing that wire bytes are the cause, which is not discoverable from any surfaced signal.

Suggested fixes

  1. Image-byte budget. Cap projected rendered bytes per request, configurable, defaulting somewhere safely under the onset (18 MiB would sit inside a 341-request zone with zero observed failures). When the next block would cross the cap, pass it through as text instead of rendering it. Degraded savings beats a failed request.
  2. Always leave compaction an escape hatch. Compaction and summarization requests should bypass compression, or use a much lower budget, so a session can always shrink itself back under the line.
  3. Graceful degradation on large-payload failures. For payloads above the threshold, retry once with compression disabled on 500, 502, or empty 200, rather than surfacing a hard API error.
  4. Surface wire bytes. Show rendered payload bytes and image count per request in the dashboard, with a warning as the cap approaches. Token savings alone actively hides this failure.

Environment

  • pxpipe-proxy 0.11.1
  • Claude Code 2.1.220 (CLI), 2.1.219 (desktop bundle)
  • Node v22.18.0
  • macOS (Darwin 25.5.0), Apple Silicon
  • Models: claude-opus-5 (1M context, launched as --model opus[1m]) and claude-fable-5
  • Upstream: api.anthropic.com via a local proxy chain

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions