Skip to content

Commit cf773fc

Browse files
authored
fix(sveltekit): Avoid capturing 404 errors on client side (#9902)
Looks like 404 errors weren't passed to the client side `handleError` hook in Kit 1.x but in 2.x they're now passed into the hook. This means, we need to filter them out.
1 parent cef3621 commit cf773fc

File tree

3 files changed

+40
-8
lines changed

3 files changed

+40
-8
lines changed

packages/e2e-tests/test-applications/sveltekit-2/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"@sveltejs/adapter-auto": "^3.0.0",
2525
"@sveltejs/adapter-node": "^2.0.0",
2626
"@sveltejs/kit": "^2.0.0",
27+
"@sveltejs/vite-plugin-svelte": "^3.0.0",
2728
"svelte": "^4.2.8",
2829
"svelte-check": "^3.6.0",
2930
"ts-node": "10.9.1",

packages/sveltekit/src/client/handleError.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,37 @@ function defaultErrorHandler({ error }: Parameters<HandleClientError>[0]): Retur
1111
});
1212
}
1313

14-
// TODO: add backwards-compatible type for kit 1.x (soon)
1514
type HandleClientErrorInput = Parameters<HandleClientError>[0];
1615

16+
/**
17+
* Backwards-compatible HandleServerError Input type for SvelteKit 1.x and 2.x
18+
* `message` and `status` were added in 2.x.
19+
* For backwards-compatibility, we make them optional
20+
*
21+
* @see https://kit.svelte.dev/docs/migrating-to-sveltekit-2#improved-error-handling
22+
*/
23+
type SafeHandleServerErrorInput = Omit<HandleClientErrorInput, 'status' | 'message'> &
24+
Partial<Pick<HandleClientErrorInput, 'status' | 'message'>>;
25+
1726
/**
1827
* Wrapper for the SvelteKit error handler that sends the error to Sentry.
1928
*
2029
* @param handleError The original SvelteKit error handler.
2130
*/
2231
export function handleErrorWithSentry(handleError: HandleClientError = defaultErrorHandler): HandleClientError {
23-
return (input: HandleClientErrorInput): ReturnType<HandleClientError> => {
24-
captureException(input.error, {
25-
mechanism: {
26-
type: 'sveltekit',
27-
handled: false,
28-
},
29-
});
32+
return (input: SafeHandleServerErrorInput): ReturnType<HandleClientError> => {
33+
// SvelteKit 2.0 offers a reliable way to check for a 404 error:
34+
if (input.status !== 404) {
35+
captureException(input.error, {
36+
mechanism: {
37+
type: 'sveltekit',
38+
handled: false,
39+
},
40+
});
41+
}
3042

43+
// We're extra cautious with SafeHandleServerErrorInput - this type is not compatible with HandleServerErrorInput
44+
// @ts-expect-error - we're still passing the same object, just with a different (backwards-compatible) type
3145
return handleError(input);
3246
};
3347
}

packages/sveltekit/test/client/handleError.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ describe('handleError', () => {
3838
it('invokes the default handler if no handleError func is provided', async () => {
3939
const wrappedHandleError = handleErrorWithSentry();
4040
const mockError = new Error('test');
41+
// @ts-expect-error - purposefully omitting status and message to cover SvelteKit 1.x compatibility
4142
const returnVal = await wrappedHandleError({ error: mockError, event: navigationEvent });
4243

4344
expect(returnVal).not.toBeDefined();
@@ -50,6 +51,7 @@ describe('handleError', () => {
5051
it('invokes the user-provided error handler', async () => {
5152
const wrappedHandleError = handleErrorWithSentry(handleError);
5253
const mockError = new Error('test');
54+
// @ts-expect-error - purposefully omitting status and message to cover SvelteKit 1.x compatibility
5355
const returnVal = (await wrappedHandleError({ error: mockError, event: navigationEvent })) as any;
5456

5557
expect(returnVal.message).toEqual('Whoops!');
@@ -59,4 +61,19 @@ describe('handleError', () => {
5961
expect(consoleErrorSpy).toHaveBeenCalledTimes(0);
6062
});
6163
});
64+
65+
it("doesn't capture 404 errors", async () => {
66+
const wrappedHandleError = handleErrorWithSentry(handleError);
67+
const returnVal = (await wrappedHandleError({
68+
error: new Error('404 Not Found'),
69+
event: navigationEvent,
70+
status: 404,
71+
message: 'Not Found',
72+
})) as any;
73+
74+
expect(returnVal.message).toEqual('Whoops!');
75+
expect(mockCaptureException).not.toHaveBeenCalled();
76+
// Check that the default handler wasn't invoked
77+
expect(consoleErrorSpy).toHaveBeenCalledTimes(0);
78+
});
6279
});

0 commit comments

Comments
 (0)