diff --git a/packages/cloudflare/src/request.ts b/packages/cloudflare/src/request.ts index 1ad2e1a8eb91..edc1bccef96f 100644 --- a/packages/cloudflare/src/request.ts +++ b/packages/cloudflare/src/request.ts @@ -18,6 +18,17 @@ interface RequestHandlerWrapperOptions { options: CloudflareOptions; request: Request>; context: ExecutionContext; + /** + * If true, errors will be captured, rethrown and sent to Sentry. + * Otherwise, errors are rethrown but not captured. + * + * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly. + * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error + * capturing mechanisms where this wrapper captures errors too early or too generally. + * + * @default true + */ + captureErrors?: boolean; } /** @@ -28,7 +39,7 @@ export function wrapRequestHandler( handler: (...args: unknown[]) => Response | Promise, ): Promise { return withIsolationScope(async isolationScope => { - const { options, request } = wrapperOptions; + const { options, request, captureErrors = true } = wrapperOptions; // In certain situations, the passed context can become undefined. // For example, for Astro while prerendering pages at build time. @@ -67,7 +78,9 @@ export function wrapRequestHandler( try { return await handler(); } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + if (captureErrors) { + captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + } throw e; } finally { waitUntil?.(flush(2000)); @@ -91,7 +104,9 @@ export function wrapRequestHandler( setHttpStatus(span, res.status); return res; } catch (e) { - captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + if (captureErrors) { + captureException(e, { mechanism: { handled: false, type: 'cloudflare' } }); + } throw e; } finally { waitUntil?.(flush(2000)); diff --git a/packages/cloudflare/test/request.test.ts b/packages/cloudflare/test/request.test.ts index 32bc8068ba6d..eb2989437396 100644 --- a/packages/cloudflare/test/request.test.ts +++ b/packages/cloudflare/test/request.test.ts @@ -212,6 +212,33 @@ describe('withSentry', () => { expect(thrownError).toBe(error); }); + + test("doesn't capture errors if `captureErrors` is false", async () => { + const captureExceptionSpy = vi.spyOn(SentryCore, 'captureException'); + const error = new Error('test'); + + expect(captureExceptionSpy).not.toHaveBeenCalled(); + let thrownError: Error | undefined; + + try { + await wrapRequestHandler( + { + options: MOCK_OPTIONS, + request: new Request('https://example.com'), + context: createMockExecutionContext(), + captureErrors: false, + }, + () => { + throw error; + }, + ); + } catch (e: any) { + thrownError = e; + } + + expect(captureExceptionSpy).not.toHaveBeenCalled(); + expect(thrownError).toBe(error); + }); }); describe('tracing instrumentation', () => {