diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/capture-metadata/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/capture-metadata/page.tsx new file mode 100644 index 000000000000..15d10d763a6d --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/capture-metadata/page.tsx @@ -0,0 +1,15 @@ +import { captureException } from '@sentry/nextjs'; +import type { Metadata } from 'next'; + +/** + * Calling captureException synchronously inside generateMetadata + * during `next build` prerender (cacheComponents). uuid4 -> crypto.randomUUID() runs + */ +export const generateMetadata = (): Metadata => { + captureException(new Error('diagnostic: data missing for this page')); + return { title: 'capture-metadata' }; +}; + +export default function Page() { + return

capture-metadata

; +} diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/tests/cacheComponents.spec.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/tests/cacheComponents.spec.ts index 0be0e2e6e3a6..29c90f5bc423 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/tests/cacheComponents.spec.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/tests/cacheComponents.spec.ts @@ -80,3 +80,10 @@ test('Should generate metadata async', async ({ page }) => { await expect(page.locator('#todos-fetched')).toHaveText('Todos fetched: 5'); await expect(page).toHaveTitle('Product: 1'); }); + +test('Should prerender a page that captures an exception in generateMetadata', async ({ page }) => { + await page.goto('/capture-metadata'); + + await expect(page).toHaveTitle('capture-metadata'); + await expect(page.locator('h1')).toHaveText('capture-metadata'); +}); diff --git a/packages/nextjs/src/server/index.ts b/packages/nextjs/src/server/index.ts index b22ba38ecd83..6ee3f9a5bb98 100644 --- a/packages/nextjs/src/server/index.ts +++ b/packages/nextjs/src/server/index.ts @@ -42,6 +42,9 @@ const globalWithInjectedValues = GLOBAL_OBJ as typeof GLOBAL_OBJ & { _sentryRelease?: string; }; +// Call at module level so `next build` prerender workers still register the runner without `init` +prepareSafeIdGeneratorContext(); + /** * A passthrough error boundary for the server that doesn't depend on any react. Error boundaries don't catch SSR errors * so they should simply be a passthrough.