Conversation
Nothing bounded how much the client would read. Net::HTTP buffers a whole response before handing it over, so a hostile endpoint, a proxy serving a runaway error page, or a compromised upstream could hand back gigabytes and the first code with an opinion about it was JSON.parse, by which time the bytes were already resident. Error bodies were worse: they are kept on the ApiError, so an oversized 500 body outlived the request. Cap it. max_response_bytes defaults to 10 MiB, which no decision response approaches -- the entire request is capped at 64k tokens and the answers are smaller than the questions -- so the limit only ever bites on something that has gone wrong. The default transport now reads in chunks and stops at the ceiling rather than collecting the body first, and an honest Content-Length over the limit ends it before a single chunk arrives. A body from a custom transport is measured on the way back, which cannot un-read it but does keep it out of the parser and off the exception. ResponseTooLarge is a RubyDecisionModel::Error, so the retry loop passes it straight through: reading a too-large body again would only be slower. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nothing bounded how much the client would read.
Net::HTTPbuffers a whole response before handing it over, so a hostile endpoint, a proxy serving a runaway error page, or a compromised upstream could hand back gigabytes and the first code with an opinion about it wasJSON.parse— by which time the bytes were already resident. Error bodies are worse: they're retained on theApiError, so an oversized 500 body outlives the request.The fix
max_response_bytes, 10 MiB by default,nilto disable. No decision response approaches that — the whole request is capped at 64k tokens and the answers are smaller than the questions — so the limit only ever bites on something that has gone wrong.The default transport now reads in chunks and stops at the ceiling rather than collecting the body first, and an honest
Content-Lengthover the limit ends it before a single chunk arrives. A body from a custom transport is measured on the way back, which cannot un-read it but does keep it out of the parser and off the exception.ResponseTooLargeis aRubyDecisionModel::Error, so the retry loop passes it straight through: reading a too-large body again would only be slower. It carries#bytesand#limit.Tests
test/response_size_test.rb, 9 cases. Three of them stand up a real loopback HTTP server rather than stubbing, so the streaming path is exercised for real: one offers 600 KiB withTransfer-Encoding: chunkedand asserts the client gave up long before receiving it all, one asserts an oversizedContent-Lengthis refused before reading, one asserts a normal body still round-trips. Suite green on 3.2.11 / 3.3.8 / 3.4.8.One of a series from a security and API-coverage audit. Branches are independent, each off
main.🤖 Generated with Claude Code