Skip to content

Stream npm packuments and fail on oversized responses - #109

Open
andrew wants to merge 2 commits into
mainfrom
stream-large-responses
Open

andrew wants to merge 2 commits into
mainfrom
stream-large-responses

Conversation

@andrew

@andrew andrew commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Closes #29

client.Client read bodies through io.LimitReader at 10 MiB and returned the truncated bytes with no error, so every npm full packument over that size failed with unexpected end of JSON input: renovate, next, typescript, @types/node and aws-sdk among them (numbers in #29).

Buffered reads (GetBody, GetJSON, GetText) now read one byte past the limit and return ErrResponseTooLarge when it arrives, without retrying. The limit is per client: MaxResponseSize or WithMaxResponseSize, defaulting to 10 MiB as before.

StreamJSON(ctx, url, fn) passes a json.Decoder over the response body to fn, with the same retries for getting a response and its own limit (MaxStreamSize, WithMaxStreamSize, default 512 MiB) that also fails with ErrResponseTooLarge rather than ending the stream early. The request and retry loop is split out as open, which returns the response with its body unread, so both paths share it.

All five npm reads (FetchPackage, FetchVersions, FetchVersion, FetchDependencies, FetchMaintainers) now decode the packument from the body: top-level fields into a header, each entry in versions decoded or skipped as it arrives, so the document is never held whole. time comes after versions on registry.npmjs.org, so publication times are filled in at the end. FetchPackage decodes only the latest version when dist-tags arrives first, and keeps versions raw only when it doesn't.

Against registry.npmjs.org, renovate (72.6 MB, 5747 versions) now resolves with a peak heap of 22 MB, and next, typescript, vite and aws-sdk all resolve with publication times on every version. On a local copy of renovate's packument, raising the limit and decoding into the old structs instead peaked at about 148 MB on top of the 72.6 MB body.

https://claude.ai/code/session_01NxsA75HBjdWQKcdx7FDTDc

Bodies over the buffered limit returned truncated bytes, so every npm
packument over 10 MiB failed to decode. Buffered reads now return
ErrResponseTooLarge, and npm packuments are decoded from the body.

Claude-Session: https://claude.ai/code/session_01NxsA75HBjdWQKcdx7FDTDc
Copilot AI balanced review requested due to automatic review settings October 18, 2026 19:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

client: silent truncation at maxResponseSize produces confusing downstream errors

2 participants