Skip to content

breaking: pass all errors through handleError, update the function contract - #16664

Merged
elliott-with-the-longest-name-on-github merged 22 commits into
version-3from
elliott/update-handle-error
Aug 10, 2026
Merged

breaking: pass all errors through handleError, update the function contract#16664
elliott-with-the-longest-name-on-github merged 22 commits into
version-3from
elliott/update-handle-error

Conversation

@elliott-with-the-longest-name-on-github

Copy link
Copy Markdown
Contributor

closes #16413

Two substantive changes:

  • handleError now handles all errors
  • errors are now categorized as "unexpected", "expected", and "framework":
    • unexpected errors are those your code (or library code you're using) throws
    • expected errors are those you throw via the error helper
    • framework errors are those which originate inside SvelteKit

These are passed into handleError as a kind, error union, where the type of error depends on the kind:

  • unexpected errors are unknown
  • expected errors are App.Error
  • framework errors are { message: string, status: string }

handleError must return App.Error, though status and message are optional (the framework will generate them automatically if you don't provide them). So the following is valid for just logging:

export function handleError({ kind, error }) {
  if (kind === 'unexpected') {
    sendToDatadog(error);
  }
}

But you can also:

export function handleError({ kind, error }) {
  if (kind === 'unexpected') {
    sendToDatadog(error);
    if (error instanceof DatabaseClientNotFoundError) {
      return { status: 404, message: 'Entity not found' }
    }
  }
}

@pkg-svelte-dev

pkg-svelte-dev Bot commented Aug 5, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 0841f37:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/0841f3722b7ffd0c2658ed729af4824e89d1d025

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16664

@changeset-bot

changeset-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0841f37

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

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Major

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

@svelte-docs-bot

Copy link
Copy Markdown

@vercel vercel Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

Prerendered remote-function errors are re-processed by handleError and misclassified as expected on the server because prerender.js throws a plain HttpError and handle_error_and_jsonify lacks a HandledHttpError short-circuit

Fix on Vercel

Comment thread documentation/docs/30-advanced/10-advanced-routing.md Outdated
Comment thread documentation/docs/20-core-concepts/60-remote-functions.md Outdated
Comment thread documentation/docs/30-advanced/20-hooks.md Outdated
Comment on lines +191 to +197
Alongside the `event`, the hook receives a `kind` discriminant that tells you where the error came from, and the `error` itself:

| `kind` | thrown by | `error` | defaults to |
| -------------- | ----------------------------------- | -------------------------------------------------------------------- | -------------------------------------------- |
| `'expected'` | [`error(...)`](@sveltejs-kit#error) | the error body, which matches [`App.Error`](types#Error) | the error body itself |
| `'unexpected'` | your code, or code it calls | the thrown value, which may contain information unsafe to expose | `{ status: 500, message: 'Internal Error' }` |
| `'framework'` | SvelteKit — 404s, 405s, 413s... | `{ status, message }`, where `message` is safe text like `Not Found` | that same `{ status, message }` |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a better suggestion to hand, but this table looks kinda goofy

image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's kinda weird, I wonder if there's a way to get the header formatting better...

Comment thread documentation/docs/30-advanced/20-hooks.md Outdated
Comment thread documentation/docs/30-advanced/20-hooks.md Outdated
Comment thread documentation/docs/30-advanced/20-hooks.md Outdated
Comment thread documentation/docs/30-advanced/25-errors.md Outdated
Comment thread documentation/docs/30-advanced/25-errors.md Outdated
@Rich-Harris

Copy link
Copy Markdown
Member

looks like some tests need updating

Comment thread packages/kit/src/runtime/server/errors.js Outdated
Comment thread packages/kit/src/runtime/server/errors.js
Comment thread packages/kit/src/runtime/server/errors.js Outdated
Comment thread packages/kit/src/exports/public.d.ts Outdated
Comment thread packages/kit/src/runtime/client/client.js Outdated
Comment thread packages/kit/test/apps/basics/src/hooks.server.js Outdated
Comment thread packages/kit/test/apps/dev-only/src/hooks.client.js Outdated
Comment thread packages/kit/test/apps/dev-only/src/hooks.server.js Outdated
Comment thread packages/kit/test/apps/basics/src/hooks.server.js Outdated
@elliott-with-the-longest-name-on-github
elliott-with-the-longest-name-on-github force-pushed the elliott/update-handle-error branch 2 times, most recently from cd174e9 to c75edb4 Compare August 7, 2026 13:35
Comment thread documentation/docs/30-advanced/20-hooks.md Outdated
Comment thread documentation/docs/30-advanced/25-errors.md Outdated

@Rich-Harris Rich-Harris left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM aside from the naming

}
```

The object you return becomes the body of an [expected error](errors#Expected-errors), which then passes through [`handleError`](hooks#handleError) with `kind: 'app'`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably update the headings on this page to 'App errors' and 'Unknown errors'

Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
@elliott-with-the-longest-name-on-github
elliott-with-the-longest-name-on-github merged commit 031ac69 into version-3 Aug 10, 2026
26 of 27 checks passed
@elliott-with-the-longest-name-on-github
elliott-with-the-longest-name-on-github deleted the elliott/update-handle-error branch August 10, 2026 21:32
teemingc added a commit that referenced this pull request Aug 11, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/kit@3.0.0-next.19

### Major Changes

- breaking: move `defineParams` and associated types to
`@sveltejs/kit/params`
([#16716](#16716))

- breaking: run all errors through the `handleError` hook
([#16664](#16664))

- breaking: move `Page`, `ReadonlyURL` and `ReadonlyURLSearchParams`
from `@sveltejs/kit` to `$app/state`
([#16694](#16694))

- breaking: move `BeforeNavigate`, `OnNavigate`, `AfterNavigate`,
`Navigation`, `NavigationTarget`, `NavigationType`, `GotoOptions` and
the `Navigation*` variant types from `@sveltejs/kit` to
`$app/navigation` ([#16694](#16694))

- breaking: move `ActionResult` and `SubmitFunction` from
`@sveltejs/kit` to `$app/forms`
([#16694](#16694))

- breaking: remove `handleValidationError` and pass remote function
validation errors to `handleError` with `kind: 'validation'`
([#16672](#16672))

### Minor Changes

- feat: ignore files with + prefix if they contain test/spec/stories
([#16715](#16715))

### Patch Changes

- fix: rebuild the dev manifest when route files disappear during an
incremental update
([#16643](#16643))

- fix: externalize `@opentelemetry/api` to prevent bundler chunk
colocation between `instrumentation.server.js` and application code
([#16302](#16302))

- fix: surface prerender errors during development
([#16507](#16507))
## @sveltejs/adapter-node@6.0.0-next.9

### Patch Changes

- fix: externalize `@opentelemetry/api` to prevent bundler chunk
colocation between `instrumentation.server.js` and application code
([#16302](#16302))
- Updated dependencies
[[`04f9ab4`](04f9ab4),
[`1e198bd`](1e198bd),
[`813726d`](813726d),
[`a115a7b`](a115a7b),
[`031ac69`](031ac69),
[`dc7442c`](dc7442c),
[`19c4478`](19c4478),
[`dc7442c`](dc7442c),
[`dc7442c`](dc7442c),
[`0b3e2b3`](0b3e2b3)]:
  - @sveltejs/kit@3.0.0-next.19

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Tee Ming <chewteeming01@gmail.com>
teemingc pushed a commit that referenced this pull request Aug 11, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/kit@3.0.0-next.19

### Major Changes

- breaking: move `defineParams` and associated types to
`@sveltejs/kit/params`
([#16716](#16716))

- breaking: run all errors through the `handleError` hook
([#16664](#16664))

- breaking: move `Page`, `ReadonlyURL` and `ReadonlyURLSearchParams`
from `@sveltejs/kit` to `$app/state`
([#16694](#16694))

- breaking: move `BeforeNavigate`, `OnNavigate`, `AfterNavigate`,
`Navigation`, `NavigationTarget`, `NavigationType`, `GotoOptions` and
the `Navigation*` variant types from `@sveltejs/kit` to
`$app/navigation` ([#16694](#16694))

- breaking: move `ActionResult` and `SubmitFunction` from
`@sveltejs/kit` to `$app/forms`
([#16694](#16694))

- breaking: remove `handleValidationError` and pass remote function
validation errors to `handleError` with `kind: 'validation'`
([#16672](#16672))

### Minor Changes

- feat: ignore files with + prefix if they contain test/spec/stories
([#16715](#16715))

### Patch Changes

- fix: rebuild the dev manifest when route files disappear during an
incremental update
([#16643](#16643))

- fix: externalize `@opentelemetry/api` to prevent bundler chunk
colocation between `instrumentation.server.js` and application code
([#16302](#16302))

- fix: surface prerender errors during development
([#16507](#16507))

- fix: adjust error overload for optional `App.Error` parameters
([#16725](#16725))
## @sveltejs/adapter-node@6.0.0-next.9

### Patch Changes

- fix: externalize `@opentelemetry/api` to prevent bundler chunk
colocation between `instrumentation.server.js` and application code
([#16302](#16302))
- Updated dependencies
[[`04f9ab4`](04f9ab4),
[`1e198bd`](1e198bd),
[`813726d`](813726d),
[`a115a7b`](a115a7b),
[`031ac69`](031ac69),
[`dc7442c`](dc7442c),
[`19c4478`](19c4478),
[`dc7442c`](dc7442c),
[`dc7442c`](dc7442c),
[`0b3e2b3`](0b3e2b3),
[`c5d0ce2`](c5d0ce2)]:
  - @sveltejs/kit@3.0.0-next.19

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
elliott-with-the-longest-name-on-github pushed a commit that referenced this pull request Aug 22, 2026
`packages/kit/test/apps/basics/test/setup.js` changes directory to
`src/routes/routing` to create the route symlink, then deletes
`test/errors.jsonl` with a path relative to the app root. On non-Windows
the `chdir` happens first, so the delete resolves under
`src/routes/routing/` and the log written by `hooks.server.js` is never
cleared between runs on Linux and macOS. `read_errors` in
`test/utils.js` picks the last record matching a path, so a stale record
from an earlier run can satisfy an assertion. The `rmSync` came in with
#16664; the `chdir` block predates it.

Node resolves a symlink's target relative to the link's own directory,
so the symlink can be created from the app root. Dropping the `chdir`
keeps every path in the script relative to the same place, so line order
can't matter again.
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.

Either don't pass internal errors to handleError, or flag them

2 participants