diff --git a/packages/sveltekit/src/server/handleError.ts b/packages/sveltekit/src/server/handleError.ts index 4d886fc80224..022c1c814930 100644 --- a/packages/sveltekit/src/server/handleError.ts +++ b/packages/sveltekit/src/server/handleError.ts @@ -21,6 +21,10 @@ function defaultErrorHandler({ error }: Parameters[0]): Retur */ export function handleErrorWithSentry(handleError: HandleServerError = defaultErrorHandler): HandleServerError { return (input: { error: unknown; event: RequestEvent }): ReturnType => { + if (isNotFoundError(input)) { + return handleError(input); + } + captureException(input.error, scope => { scope.addEventProcessor(event => { addExceptionMechanism(event, { @@ -35,3 +39,25 @@ export function handleErrorWithSentry(handleError: HandleServerError = defaultEr return handleError(input); }; } + +/** + * When a page request fails because the page is not found, SvelteKit throws a "Not found" error. + * In the error handler here, we can't access the response yet (which we do in the load instrumentation), + * so we have to check if the error is a "Not found" error by checking if the route id is missing and + * by checking the error message on top of the raw stack trace. + */ +function isNotFoundError(input: { error: unknown; event: RequestEvent }): boolean { + const { error, event } = input; + + const hasNoRouteId = !event.route || !event.route.id; + + const rawStack: string = + (error != null && + typeof error === 'object' && + 'stack' in error && + typeof error.stack === 'string' && + error.stack) || + ''; + + return hasNoRouteId && rawStack.startsWith('Error: Not found:'); +} diff --git a/packages/sveltekit/test/server/handleError.test.ts b/packages/sveltekit/test/server/handleError.test.ts index e44d5553f928..12ecb83b44e6 100644 --- a/packages/sveltekit/test/server/handleError.test.ts +++ b/packages/sveltekit/test/server/handleError.test.ts @@ -47,6 +47,23 @@ describe('handleError', () => { mockScope = new Scope(); }); + it('doesn\'t capture "Not found" errors for incorrect navigations', async () => { + const wrappedHandleError = handleErrorWithSentry(); + const mockError = new Error('Not found: /asdf/123'); + const mockEvent = { + url: new URL('https://myDomain.com/asdf/123'), + route: { id: null }, // <-- this is what SvelteKit puts in the event when the page is not found + // ... + } as RequestEvent; + + const returnVal = await wrappedHandleError({ error: mockError, event: mockEvent }); + + expect(returnVal).not.toBeDefined(); + expect(mockCaptureException).toHaveBeenCalledTimes(0); + expect(mockAddExceptionMechanism).toHaveBeenCalledTimes(0); + expect(consoleErrorSpy).toHaveBeenCalledTimes(1); + }); + describe('calls captureException', () => { it('invokes the default handler if no handleError func is provided', async () => { const wrappedHandleError = handleErrorWithSentry();