Skip to content

@sentry/nextjs aborts Next.js Cache Components renders on Cloudflare Workers when requests overlap #25245

Description

@NathanDrake2406

Is there an existing issue for this?

How do you use Sentry?

Not relevant. The problem occurs with Sentry.init({}) and no DSN.

Which SDK are you using?

@sentry/nextjs

SDK Version

11.6.0 and 10.71.0. Both are affected. The stack and the two Sentry.init option rows below are from 10.71.0.

Framework Version

Next.js 16.3.8 with cacheComponents: true, on Cloudflare Workers (@opennextjs/cloudflare 1.20.10 and the build of opennextjs/opennextjs-cloudflare#1318, workerd 1.20261006.1, compatibility date 2025-09-15)

Link to Sentry event

No response

Reproduction Example/SDK Setup

https://github.com/kmsomebody/cache-components-repro

instrumentation.ts calls Sentry.init({}) for the nodejs runtime.

I changed these versions in the repository: next 16.3.8, @opennextjs/cloudflare 1.20.10, wrangler 4.149.0, @sentry/nextjs 11.6.0. For 11.6.0, next.config.ts imports withSentryConfig from @sentry/nextjs/config.

Steps to Reproduce

  1. Build the app with opennextjs-cloudflare build and start it with opennextjs-cloudflare preview.
  2. Open / in a browser. The page prefetches /static and /dynamic.
  3. Look at the two prefetch requests that have the header next-router-prefetch: 3.

Three requests in flight are necessary. Sequential requests are correct.

Expected Result

The responses are the same as with next start. The /static prefetch has 174538 bytes and the /dynamic prefetch has 1970 bytes.

Actual Result

The body of each prefetch is one byte, ~, which is the Next.js marker for a partial response. This occurs in 28 to 30 of 30 concurrent requests. With next start, it occurs in 0 of 30.

Additional Context

prepareSafeIdGeneratorContext keeps one AsyncLocalStorage.snapshot() for all requests. On workerd, a snapshot is bound to the request that made it. This is the default from compatibility date 2025-06-16. When a different request calls the snapshot, it throws. The wrapper then takes a new snapshot in the current context and stores it for all requests.

When requests overlap, a request finds a snapshot from a different request while it renders. It takes the new snapshot inside the Next.js prerender context, so the "safe" context is no longer outside the render. uuid4 then calls crypto.randomUUID() there, and Next.js stops the prerender. This is the stack, with the minified names replaced:

Route /static needs to bail out of prerendering at this point because it used `crypto.randomUUID()`.
    at abortOnSynchronousPlatformIOAccess
    at io
    at webCrypto.randomUUID
    at withRandomSafeContext
    at uuid4
    at generateTraceId
    at new Scope
    at Scope.clone
    at buildContextWithSentryScopes
    at SentryAsyncLocalStorageContextManager.with
    at ContextAPI.with
    at NextTracerImpl.trace

Results with 30 concurrent prefetch requests for each route:

Change One-byte bodies
None, Sentry.init({}) 28 to 30 of 30
Sentry.init({ enabled: false }) 29 to 30 of 30
Sentry.init({ skipOpenTelemetrySetup: true }) 0 of 30
workerd flag do_not_bind_asynclocalstorage_snapshot_to-request 0 of 30

The worker bundle contains the Node.js server build of the SDK, not the edge build.

#21510 was a different cause of the same Next.js error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions