Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/seven-mangos-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': minor
---

feat: allow returning a custom HTTP status code from the `handleError` hook
3 changes: 2 additions & 1 deletion documentation/docs/30-advanced/20-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,9 @@ If an [unexpected error](errors#Unexpected-errors) is thrown during loading, ren

- you can log the error
- you can generate a custom representation of the error that is safe to show to users, omitting sensitive details like messages and stack traces. The returned value, which defaults to `{ message }`, becomes the value of `$page.error`.
- you can customise the status code of the response

For errors thrown from your code (or library code called by your code) the status will be 500 and the message will be "Internal Error". While `error.message` may contain sensitive information that should not be exposed to users, `message` is safe (albeit meaningless to the average user).
For errors thrown from your code (or library code called by your code) the status will default to 500 and the message will default to "Internal Error". While `error.message` may contain sensitive information that should not be exposed to users, `message` is safe (albeit meaningless to the average user).

To add more information to the `$page.error` object in a type-safe way, you can customize the expected shape by declaring an `App.Error` interface (which must include `message: string`, to guarantee sensible fallback behavior). This allows you to — for example — append a tracking ID for users to quote in correspondence with your technical support staff:

Expand Down
10 changes: 9 additions & 1 deletion packages/kit/src/utils/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,17 @@ export function normalize_error(error) {

/**
* @param {unknown} error
* @returns {number}
*/
export function get_status(error) {
return error instanceof HttpError || error instanceof SvelteKitError ? error.status : 500;
if (error instanceof HttpError || error instanceof SvelteKitError) {
return error.status;
}
// For overrides / custom error objects
if (typeof error === 'object' && error !== null && 'status' in error) {
return /** @type {{ status?: number }} */ (error).status ?? 500;
}
return 500;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CustomError extends Error {
constructor(message, errorOpts) {
super(message, errorOpts);
this.status = 422;
}
}

export function GET() {
throw new CustomError('Custom error');
}
5 changes: 5 additions & 0 deletions packages/kit/test/apps/basics/test/server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,11 @@ test.describe('Errors', () => {
expect(await response.text()).toMatch('thisvariableisnotdefined is not defined');
});

test('custom error object', async ({ request }) => {
const response = await request.get('/errors/custom-error');
expect(response.status()).toBe(422);
});

test('returns 400 when accessing a malformed URI', async ({ page }) => {
const response = await page.goto('/%c0%ae%c0%ae/etc/passwd');
if (process.env.DEV) {
Expand Down
Loading