Summary
The generated Fetch client decides whether to call response.json() or response.text() by checking whether the Content-Type header starts with one of the known JSON media types:
const jsonTypes = ['application/json', 'application/problem+json'];
const isJSON = jsonTypes.some(type =>
contentType.toLowerCase().startsWith(type),
);
In some Firefox sessions, Response.headers.get('content-type') can intermittently expose a comma-separated value containing an unexpected media type before the actual one, for example:
text/html,application/json
When the response body is JSON, the generated client consequently calls response.text() and returns a string instead of the expected parsed object.
Mozilla Bugzilla has a report showing the same browser-level symptom: Firefox returned a comma-separated Content-Type containing an unexpected value followed by the actual response media type:
https://bugzilla.mozilla.org/show_bug.cgi?id=2047399
That report was resolved as WORKSFORME after the intermittent behavior could no longer be reproduced, so applications may still need a defensive workaround for affected Firefox versions or sessions.
Deterministic reproduction of the generated-client behavior
The browser bug itself is intermittent, but the behavior of the generated parser can be reproduced independently:
const response = new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: {
'Content-Type': 'text/html,application/json',
},
});
const result = await getResponseBody(response);
console.log(result); // '{"ok":true}'
console.log(typeof result); // 'string'
Expected behavior
There should be a straightforward supported way for generated Fetch clients to defensively recognize JSON when a browser exposes a comma-separated header containing a JSON media type, without editing generated files.
Possible approaches could include:
- treating each comma-separated media-type candidate independently;
- exposing a small response-body parser hook or response transformer;
- allowing the JSON content-type predicate to be overridden.
Current workaround
The existing --request <custom-request> option can work around the problem, but it requires copying and maintaining the complete request implementation only to customize this small parsing decision. A narrower extension point or built-in defensive handling would be significantly easier to maintain.
This is related to, but not fully covered by, #386: startsWith() handles media-type parameters when JSON is first, but does not handle an unexpected media type appearing before the JSON type.
Summary
The generated Fetch client decides whether to call
response.json()orresponse.text()by checking whether theContent-Typeheader starts with one of the known JSON media types:In some Firefox sessions,
Response.headers.get('content-type')can intermittently expose a comma-separated value containing an unexpected media type before the actual one, for example:When the response body is JSON, the generated client consequently calls
response.text()and returns a string instead of the expected parsed object.Mozilla Bugzilla has a report showing the same browser-level symptom: Firefox returned a comma-separated
Content-Typecontaining an unexpected value followed by the actual response media type:https://bugzilla.mozilla.org/show_bug.cgi?id=2047399
That report was resolved as
WORKSFORMEafter the intermittent behavior could no longer be reproduced, so applications may still need a defensive workaround for affected Firefox versions or sessions.Deterministic reproduction of the generated-client behavior
The browser bug itself is intermittent, but the behavior of the generated parser can be reproduced independently:
Expected behavior
There should be a straightforward supported way for generated Fetch clients to defensively recognize JSON when a browser exposes a comma-separated header containing a JSON media type, without editing generated files.
Possible approaches could include:
Current workaround
The existing
--request <custom-request>option can work around the problem, but it requires copying and maintaining the complete request implementation only to customize this small parsing decision. A narrower extension point or built-in defensive handling would be significantly easier to maintain.This is related to, but not fully covered by, #386:
startsWith()handles media-type parameters when JSON is first, but does not handle an unexpected media type appearing before the JSON type.