Middleware error handling: returning custom values from catch blocks doesn't reach the client
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 15.1k
- Forks
- 1.9k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 143
Description
Problem
We use function middleware to catch errors and convert them to structured error responses so the client can branch on error codes (show field-level validation errors, redirect on auth failures, show billing-specific messages, etc.).
export const errorHandler = createMiddleware({ type: 'function' }).server(async ({ next }) => {
try {
return await next()
} catch (error) {
if (error instanceof DomainError) {
return { success: false, error: { code: 'BILLING_ERROR', message: error.message } }
}
return { success: false, error: { code: 'INTERNAL_SERVER_ERROR', message: 'Something went wrong' } }
}
})
Registered globally:
createStart(() => ({
functionMiddleware: [errorHandler],
}))
Expected: Client receives { success: false, error: { code: 'BILLING_ERROR', ... } } as the resolved value.
Actual: Client promise rejects with just the inner error object { code: 'BILLING_ERROR', ... }. The { success: false } wrapper is stripped.
Root cause
executeMiddleware uses { result, error } internally (ServerFnMiddlewareResult). When middleware returns an object with an .error property, line 140 of createServerFn.ts treats it as a middleware-chain error and throws it:
if (result.error) throw result.error
Any return value from middleware that has a truthy .error field collides with this internal protocol. The middleware's return is never delivered to the client as a resolved value.
What we need
We want a global error boundary for server functions — similar to FastAPI exception handlers or Express error middleware. The goal is:
- Classified errors (auth, billing, validation) — send a structured error code to the client so it can react (redirect, show field errors, show billing prompts)
- Unexpected errors — log server-side for debugging, send a generic "Something went wrong" to the client
- Single boundary — handlers just throw, middleware handles classification
Questions
- Is returning custom values from middleware catch blocks intended to work? The docs only show
return next()orthrowfrom middleware — never custom returns. - If not, what's the recommended pattern for global error classification in server functions? Should middleware
throwa structured error object and let the client catch the rejection? - Would TanStack consider documenting an official error-handling middleware pattern?
Environment
@tanstack/react-startv1.167.17@tanstack/start-client-corev1.167.17
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with createServerFn.ts around line 140 and trace executeMiddleware and ServerFnMiddlewareResult to reproduce the collision when a middleware return value has an error property. Check the existing middleware documentation and tests for the intended return and rejection contract. Done means the behavior is defined and the relevant implementation or documentation covers global error handling.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100