Repository navigation
Gateway 413 body-limit rejection is misclassified as context overflow, wedging the session #11486
akshaytp1571
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
When the configured provider sits behind a reverse proxy with a request-body limit
(nginx
client_max_body_size, for example), a turn that carries a large inlinebase64 image fails with
413 Request Entity Too Large. pi-ai's overflow patternsmatch any leading HTTP 413 status, so the harness labels the turn
CONTEXT_WINDOW_EXCEEDEDand runs compaction. Compaction cannot shrink an inlineimage payload, so the retry dies with the same 413. Every subsequent turn ends in
error and the session cannot be continued.
Environment
0.2.1-rc.2(installed npm package), host restarted after the fix below~/.dsh/sessions/<cwd>/<sessionId>/session.v4.jsonl.zstdReproduction
Observed:
turn/endwithkind: "error"and{ "code": "CONTEXT_WINDOW_EXCEEDED", "message": "413 <html>\n<head><title>413 Request Entity Too Large</title></head>\n<body>\n<center><h1>413 Request Entity Too Large</h1></center>\n<hr><center>nginx</center>\n</body>\n</html>\n" }followed by a compaction attempt that fails with the same 413. The turn repeats
indefinitely.
Root cause
packages/llm/llm-pi-ai/src/stream.tscomputespiAiOverflowthroughisContextOverflow(), which delegates to pi-ai'sOVERFLOW_PATTERNS. That listincludes
/^(?:[\w -]+ API error \(413\):|413(?:\s|:|$))/i, so any message whosetext begins with
413is treated as a context overflow regardless of what theserver actually said.
mapStopReasonchecks the pi-ai overflow result before the harness's ownclassifier, and the harness's
classifyPiAiErrormaps 413 toINVALID_REQUEST.The broad pi-ai rule therefore wins and a request-size failure is reported as a
context-window failure.
Two consequences make this worse than a wrong label:
image is retained verbatim, so the payload size never drops.
retryPolicy.maxRetriesleft high andRATE_LIMITinretryableCodes,the failure loop presents as a hang rather than an error.
Fix
Gate the pi-ai overflow branch on a check that separates a proxy body-limit
rejection from a provider context overflow. A body-limit rejection either renders
an HTML error page or carries no JSON body; a provider overflow reports a
structured error object.
Branch:
fix/pi-ai-413-gateway-body-limitonakshaytp1571/deepseek-harness(commit69600080), based onf3803c96.mapStopReasonthen returns the overflow branch only when the pi-ai overflow isnot a gateway body limit, so a 413 page keeps the harness's own
INVALID_REQUESTclassification.Tests
packages/llm/llm-pi-ai/tests/convert.spec.ts— nginx HTML 413 and a bare413 Request Entity Too Largestatus line both map toINVALID_REQUEST; astructured
413 {"error":{"type":"request_too_large"}}body still maps toCONTEXT_WINDOW_EXCEEDED;github-copilot API error (413): {...}keeps itsexisting
INVALID_REQUESTmapping.packages/llm/llm-pi-ai/tests/adapter.spec.ts— end-to-end, a mocked 413 HTMLresponse maps to
INVALID_REQUEST.npx vitest run packages/llm/llm-pi-ai/tests/convert.spec.ts→ 83 passed.npx vitest run packages/llm/llm-pi-ai/tests/adapter.spec.ts --project process-bound→ 56 passed.npx oxlint packages/llm/llm-pi-ai→ 0 warnings, 0 errors.npx tsc -b packages/llm/llm-pi-ai/tsconfig.json→ clean.Suggested follow-ups
OVERFLOW_PATTERNS413 rule is broader than any provider contract. Aprovider that legitimately reports context overflow with a bare 413 status line
and no JSON body would now be classified
INVALID_REQUEST.dsh-compaction-image-offload) already exists and keysoff
IMAGE_OFFLOAD_REQUIRED, raised above the route'smaxRequestImageBytes.A gateway body-limit rejection could raise the same signal so large attachments
move off the request instead of failing the turn.
Severity and triage
Classification defect, not a crash. No data loss and no incorrect output; the
damage is that a request-size failure is routed to a recovery path that cannot
address it.
Latent rather than universal. The trigger is a gateway that caps the request body
below the payload size, which most self-hosted and corporate proxies do and most
direct provider endpoints do not. A deployment without a body cap never reaches
this code path.
The over-broad pattern is not in this repository.
@earendil-works/pi-ai@^1.3.0owns
OVERFLOW_PATTERNS, and its own documentation shows the413rule waswritten for Anthropic's structured body:
It was not written to match a bare status line or an HTML error page, which is
what a proxy emits. The workaround in this report lives in
mapStopReasonbecause that is the only place this repository can intercept the label; the
durable fix is narrowing the pattern in pi-ai to require a structured body.
Note also that the harness's own
classifyPiAiErroralready maps413toINVALID_REQUEST(packages/llm/llm-pi-ai/src/stream.ts), so the twoclassifiers in that module disagree about the same input by construction.
All reactions