TanStack / TanStack/router

Start: non-OK application/json response makes a server function resolve undefined instead of rejecting

Open Beginner friendly
#8,280 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

information needed
Dominant language
TypeScript
Stars
15.1k
Forks
1.9k
Avg merge
1d 20h
Merged PRs (30d)
143

Description

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
  1. pnpm install && pnpm build && pnpm start
  2. Open http://localhost:3000/?mode=json500. The fetch returns a 500 JSON body. The loader resolves with undefined.
  3. Open http://localhost:3000/?mode=text500. Same 500 as text/plain. The loader rejects.
  4. Open http://localhost:3000/?mode=noheader. Real request without x-tsr-serverFn. The server answers {"status":500,"unhandled":true,"message":"HTTPError"}, the loader resolves with undefined.
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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in start-client-core/src/client-rpc/serverFnFetcher.ts, focusing on getResponse and its application/json handling, then review the related middleware in createServerFn.ts. Run the linked reproducer with pnpm install && pnpm build && pnpm start and compare json500 with text500. Done means non-OK, unserialized JSON responses reject instead of resolving undefined.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.