Skip to content

About

Minimal repro: solid-start server function promises resolve instead of rejecting when POST /_server fails with a 500 (no X-Error header)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

5 Commits

Folders and files

Repository files navigation

solid-start server function 500 repro

Minimal reproduction: when a "use server" RPC fails below the handler (the response is a 500 without an X-Error header), the client-side promise resolves instead of rejecting, so callers mistake total server failure for success.

Run it

pnpm install
pnpm dev

Open http://localhost:3000 and click "Call server function". The page shows:

BUG: the promise RESOLVED although POST /_server failed with a 500. Result: undefined

while the terminal logs the import-time crash and POST /_server returns 500.

Why

fetchServerFunction in @solidjs/start/dist/fns/client.js only throws when the response carries an X-Error header, which is set when the handler itself throws. It never checks response.ok, so any failure that happens before the handler runs resolves the promise: with the parsed error body when its content type matches one of the parse branches (nitro's application/json error payload in production), or with undefined when none matches (this repro's dev-server HTML error page, hence Result: undefined in the UI):

if (response.headers.has("X-Error")) {
    throw result;
}
return result; // <- a 500 without X-Error falls through to here

When this happens in the real world

Any 500 produced below the server function handler:

  • A server function module that crashes at import time on the deployment runtime. This is how we hit it in production: importing the pino logger into a server function module deployed on Cloudflare Pages. pino initializes its writer sonic-boom at import time, which calls node:util inherits(SonicBoom, EventEmitter). Under workerd's nodejs_compat the bundled EventEmitter interop had no prototype, so the whole server function chunk threw a TypeError before any handler ran. The pages kept rendering (they were prerendered at build time on Node, where pino loads fine), only POST /_server died. Users submitted a contact form, saw the success state, and every message was silently lost.
  • A reverse proxy, CDN, or WAF answering with its own 5xx error page.
  • A crashed or out-of-memory worker.

src/broken.ts simulates the first case with a module that throws at import time on the server only.

Expected

The promise should reject, like a handler-thrown error does, and like server action/RPC clients in Next.js, TanStack Start, Remix, and SvelteKit behave on transport-level failures.

Related

This repro runs @solidjs/start 2.0.0-rc.5 on plain Vite and Nitro v3. The same X-Error-only logic was present in 1.x, where it was fixed by #2159, but that fix was never ported to the rewritten v2 client, so the bug is back.

About

Minimal repro: solid-start server function promises resolve instead of rejecting when POST /_server fails with a 500 (no X-Error header)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages