Repository navigation
Conversation
When a response has no Content-Type header, detectResponseType defaults to "json", so the response body is run through native JSON.parse. That parse ran before the status check and outside any try/catch, so a plain-text 4xx/5xx body (common from nginx/HAProxy/CDN error pages) threw a bare SyntaxError instead of a FetchError. That error carried no status/data, silently skipped retry for retryable codes such as 503, and bypassed ignoreResponseError/onResponseError. Wrap the parse and fall back to the raw text when it is not valid JSON. Valid JSON still parses to an object; error and non-JSON bodies resolve to a FetchError and go through the normal retry and error-handling paths. This restores the non-throwing behavior from before the switch to native JSON.parse, without re-adding the destr dependency.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/fetch.ts`:
- Around line 220-227: Scope the JSON parse fallback in fetch.ts so it only
applies to error responses, not all responses. Update the try/catch around
parseFunction(data) to preserve the current raw-text fallback only when the
response status indicates an error (for example, in the FetchResponse handling
path that builds context.response._data), and let malformed JSON on 2xx
responses surface normally. Use the existing parseFunction,
context.response._data, and FetchError/ignoreResponseError flow to locate and
adjust the logic.
In `@test/index.test.ts`:
- Around line 67-75: The `/flaky-503` test path in `test/index.test.ts` is still
returning a plain object on success, which lets h3 auto-add `Content-Type:
application/json` and defeats the missing-header scenario. Update the
`all("/flaky-503", ...)` handler so both the retry failure and the eventual
success branch return a `Response`, and explicitly delete the `content-type`
header in the success branch as well. Use the `flaky503Attempts` logic and the
`/flaky-503` handler to keep the test behavior focused on the missing-header
case.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 27c6b238-170f-44e3-b17e-cb48d7eedb27
📒 Files selected for processing (2)
src/fetch.tstest/index.test.ts
A non-JSON error response with no
Content-Typeheader throws a bareSyntaxErrorthat bypasses retry and error handling.Repro
A local server returns a plain-text
503with noContent-Typeheader, like a bare error page from nginx/HAProxy/a CDN:Fetching it:
Actual: a
SyntaxError("Unexpected token 'S'...") with no.status,.data, or.response. Because it is not aFetchError, the retry path is skipped for the retryable503, andignoreResponseError/onResponseErrornever run.Expected: a
FetchErrorwith.status === 503and.data === "Service Unavailable", retried perretryStatusCodes, and swallowed byignoreResponseError.Root cause
The response body is parsed before the status check and outside any
try/catch. When there is noContent-Type,detectResponseType("")defaults tojson, so the raw body runs through nativeJSON.parse. A non-JSON body throws, and the throw escapes before the>= 400handling inonError, so it never becomes aFetchErrorand never reaches retry or the response-error hooks.Fix
Wrap the parse and fall back to the raw text when the body is not valid JSON:
Valid JSON still parses to an object via native
JSON.parse. Error and non-JSON bodies now resolve to aFetchErrorcarrying the status and the raw text, so they flow through the normal retry and error-handling paths. This restores the non-throwing behavior from before #520 switched the success path to nativeJSON.parse, without re-adding thedestrdependency.Tests
Added regression tests in
test/index.test.tsusing the existing local H3 server: a plain-text503withoutContent-Typeresolves to aFetchError(status503, data equal to the text) instead of aSyntaxError, that503is retried perretryStatusCodes,ignoreResponseErrorswallows it, and valid JSON still parses to an object.Verified red before the change (
SyntaxError, no retry) and green after. Full suite: 32/32 passing, lint and prettier clean.Summary by CodeRabbit
Bug Fixes
Tests