fix(http): a size refusal stops calling itself a parse error #355

Merged
coilyco-ops merged 3 commits from fix/size-refusal-is-not-a-parse-error into main 2026-08-13 11:14:20 +00:00
Member

MaxBytesReader surfaces through the decoder, and both write endpoints collapsed
every decode error into "request body must be a JSON object". A well-formed
request was told its JSON was broken, so the caller went to debug a payload
with nothing wrong with it.

Quail's reproduction on 157 is the sharp version. Twelve history entries is
within max_context_messages: 12 and each is under the rune cap, so a request
that satisfies every documented limit was called malformed. No abusive caller
is needed, just a long conversation.

Both endpoints are fixed, because fixing one would leave the identical message
on the other. They are not equally fixable: the turn endpoint gets a new
exception code, and job submission uses bare http.Error and gets an honest
message without an honest telemetry bucket. That bound is on 351 rather than
silently absorbed here.

The new code is a sibling of input_too_long, not a reuse of it. That one is the
post-decode field caps, and pointing a body cap at it would put two limits in
one bucket, which is the same defect one layer up and would leave 159 unable to
separate them. The catalog bound moves 26 to 27, which its doc requires to be a
reviewed increase rather than a silent one.

The message derives from maxHTTPBody rather than repeating the number, so the
limit stated and the limit enforced cannot drift apart.

The status code is unchanged at 400. A 413 naming the limit and the received
size is the design Kai declined on 157, and shipping it here under a
truthfulness fix would adopt a rejected decision through the side door.

Two characterization tests asserted the collision and both said to follow the
fix rather than be deleted. Both are flipped.

closes #351

Co-authored-by: Kai Siren coilysiren@gmail.com
Co-authored-by: Claude noreply@anthropic.com

MaxBytesReader surfaces through the decoder, and both write endpoints collapsed every decode error into "request body must be a JSON object". A well-formed request was told its JSON was broken, so the caller went to debug a payload with nothing wrong with it. Quail's reproduction on 157 is the sharp version. Twelve history entries is within max_context_messages: 12 and each is under the rune cap, so a request that satisfies every documented limit was called malformed. No abusive caller is needed, just a long conversation. Both endpoints are fixed, because fixing one would leave the identical message on the other. They are not equally fixable: the turn endpoint gets a new exception code, and job submission uses bare http.Error and gets an honest message without an honest telemetry bucket. That bound is on 351 rather than silently absorbed here. The new code is a sibling of input_too_long, not a reuse of it. That one is the post-decode field caps, and pointing a body cap at it would put two limits in one bucket, which is the same defect one layer up and would leave 159 unable to separate them. The catalog bound moves 26 to 27, which its doc requires to be a reviewed increase rather than a silent one. The message derives from maxHTTPBody rather than repeating the number, so the limit stated and the limit enforced cannot drift apart. The status code is unchanged at 400. A 413 naming the limit and the received size is the design Kai declined on 157, and shipping it here under a truthfulness fix would adopt a rejected decision through the side door. Two characterization tests asserted the collision and both said to follow the fix rather than be deleted. Both are flipped. closes #351 Co-authored-by: Kai Siren <coilysiren@gmail.com> Co-authored-by: Claude <noreply@anthropic.com>
fix(http): a size refusal stops calling itself a parse error
All checks were successful
ci / test (pull_request) Successful in 30s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 19s
b36066ec0e
MaxBytesReader surfaces through the decoder, and both write endpoints collapsed
every decode error into "request body must be a JSON object". A well-formed
request was told its JSON was broken, so the caller went to debug a payload
with nothing wrong with it.

Quail's reproduction on 157 is the sharp version. Twelve history entries is
within max_context_messages: 12 and each is under the rune cap, so a request
that satisfies every documented limit was called malformed. No abusive caller
is needed, just a long conversation.

Both endpoints are fixed, because fixing one would leave the identical message
on the other. They are not equally fixable: the turn endpoint gets a new
exception code, and job submission uses bare http.Error and gets an honest
message without an honest telemetry bucket. That bound is on 351 rather than
silently absorbed here.

The new code is a sibling of input_too_long, not a reuse of it. That one is the
post-decode field caps, and pointing a body cap at it would put two limits in
one bucket, which is the same defect one layer up and would leave 159 unable to
separate them. The catalog bound moves 26 to 27, which its doc requires to be a
reviewed increase rather than a silent one.

The message derives from maxHTTPBody rather than repeating the number, so the
limit stated and the limit enforced cannot drift apart.

The status code is unchanged at 400. A 413 naming the limit and the received
size is the design Kai declined on 157, and shipping it here under a
truthfulness fix would adopt a rejected decision through the side door.

Two characterization tests asserted the collision and both said to follow the
fix rather than be deleted. Both are flipped.

closes #351

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Merge branch 'main' into fix/size-refusal-is-not-a-parse-error
Some checks failed
ci / test (pull_request) Successful in 31s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Failing after 10m46s
03b09544d9
Merge branch 'main' into fix/size-refusal-is-not-a-parse-error
All checks were successful
ci / test (pull_request) Successful in 30s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 20s
baa4c14eec
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!355
No description provided.