Start: non-OK application/json response makes a server function resolve undefined instead of rejecting
Which project does this relate to?
Start
Describe the bug
A server-function call resolves with undefined when the response is not OK, is application/json, and has no x-tss-serialized header. .catch() never runs. The same 500 as text/plain rejects.
getResponse in start-client-core/src/client-rpc/serverFnFetcher.ts returns plain JSON before it checks response.ok:
if (contentType.includes('application/json')) {
const jsonPayload = await response.json()
const redirect = parseRedirect(jsonPayload)
if (redirect) throw redirect
if (isNotFound(jsonPayload)) throw jsonPayload
return jsonPayload
}
if (!response.ok) {
throw new Error(await response.text())
}The middleware in createServerFn.ts spreads that body into the call context and returns result.result, so an error body without a result key becomes undefined. A body with an error key is thrown as-is.
Any JSON error response between browser and server does this: a gateway 502 page, a proxy, or the server's own unhandled 500 when x-tsr-serverFn is missing (#8237).
Complete minimal reproducer
https://github.com/antur84/tanstack-start-serverfn-nonok-json-repro
Steps to Reproduce the Bug
pnpm install && pnpm build && pnpm start- Open http://localhost:3000/?mode=json500. The fetch returns a 500 JSON body. The loader resolves with
undefined. - Open http://localhost:3000/?mode=text500. Same 500 as
text/plain. The loader rejects. - Open http://localhost:3000/?mode=noheader. Real request without
x-tsr-serverFn. The server answers{"status":500,"unhandled":true,"message":"HTTPError"}, the loader resolves withundefined.
Expected behavior
A non-OK response that Start did not serialize should reject, like the text/plain path:
if (!response.ok) throw new Error(JSON.stringify(jsonPayload))Screenshots or Videos
None, the banner on each page shows the outcome.
Platform
@tanstack/react-start 1.168.50, @tanstack/react-router 1.170.33 (start-client-core 1.170.28, start-server-core 1.169.32, router-core 1.171.28), vite 8.2.2, node 24, macOS. Same code on main.
Additional context
Fixing #8237 does not close this. Any JSON error body takes the same path.
Source: TanStack/router