Skip to content

fix(server): leave unhandled errors to the server hosting the handler - #2379

Open
dennev wants to merge 2 commits into
solidjs:mainfrom
dennev:test/api-route-errors-reach-nitro
Open

dennev wants to merge 2 commits into
solidjs:mainfrom
dennev:test/api-route-errors-reach-nitro

Conversation

@dennev

@dennev dennev commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

What is the current behavior?

An error that an API route or a middleware throws never reaches Nitro's error hook or its errorHandler, because the handler answers it inside its own h3 app and its fetch never rejects. The steps and the details are in #2378. In SolidStart 1.5.1 the same API route's error reached Nitro's error hook.

What is the new behavior?

The first commit is the failing test, as in CONTRIBUTING's "Failing Test PR". The second commit is the proposed fix:

  • When a route, a middleware or the handler itself throws an error that h3 would answer as unhandled, the handler's fetch rejects with it, so the server hosting the handler answers and reports it. With Nitro, that means the error hook, then the errorHandler.
  • These cases are answered as before: an h3 HTTPError not marked unhandled, a status thrown as a number and h3's not-found and handled markers, by SolidStart; an error reached through request(), by SolidStart; an error reached through an h3 app that the handler is mounted in, by that app.
  • SolidStart's own dev server (without Nitro) shows its existing error overlay for such errors, and its preview server answers them with a 500.
  • Tests: packages/start/src/server/handler.spec.ts is new, packages/start/src/config/dev-server.spec.ts gets a test of the preview server, and the e2e test of the first commit now passes. A patch changeset is included.

Other information

This changes who answers an unhandled error:

  • The handler's fetch can now reject, unlike h3's H3.fetch. A server or adapter that calls it directly answers such an error itself.
  • The host builds the error response. With Nitro, the body is Nitro's and a custom errorHandler applies; headers set for the error response with event.res.errHeaders on SolidStart's event are not in the host's answer.

#2378 has the full list of trade-offs (including the status and headers of the answer, which errors still do not reach the hook, server function requests that fail before the function runs) and two alternatives that keep SolidStart's answers (calling Nitro's captureError, or an error option on the handler). The e2e test runs under vite dev; I also ran a production build of a new app with @solidjs/start packed from this branch: the error hook gets the API route's error and Nitro answers the 500.

I pushed the fix now, rather than waiting for an answer on the approach, so that the approach can be judged with the code. If you prefer one of the alternatives or another approach, I will change this pull request.

A failing test: an error that an API route throws never reaches Nitro's
`error` hook, because the handler answers it inside its own h3 app. A Nitro
plugin in the test app names the error its `error` hook received in a
response header, and the test checks that header.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@netlify

netlify Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

👷 Deploy request for solid-start-landing-page pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit e8441f8

@changeset-bot

changeset-bot Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e8441f8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/start Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/start@2379

commit: e8441f8

The handler answered every error it caught inside its own h3 app, so its
`fetch` never rejected and the server hosting it never saw an error that an
API route or middleware threw. With Nitro, the `error` hook, where error
reporters capture server errors, and the `errorHandler` did not run for it;
SolidStart's own dev server never reached its error overlay.

A `fetch` call now rejects when a route, a middleware or the handler throws
an error that h3 would answer as unhandled for the request passed to that
call: with the thrown `Error`, or with an unhandled 500 caused by a thrown
value that is not one, or by another library's error named `HTTPError`. An
h3 `HTTPError` not marked unhandled, a status thrown as a number, or h3's
not-found and handled markers are answered as before, and so is an error
reached through `request()`, also during a `fetch` call; an h3 app the
handler is mounted in, or one that enters it through its `handler`, gets
the error, as before. Each call keeps its own state, so overlapping calls,
also with one `Request`, do not mix their errors. The preview server
answers a rejected `fetch` with a 500. Headers set for the error response
with `event.res.errHeaders` are not part of the host's answer.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dennev dennev changed the title test: pass an error thrown by an API route to Nitro's error hook fix(server): leave unhandled errors to the server hosting the handler Nov 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug?]: Errors thrown by API routes and middleware never reach Nitro's error hook

2 participants