AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

CacheComponents: @Vercel/Otel'S Http Instrumentation Tracer Acquired During Register() Bypasses AfterRegistration Span Patch Causing Math.Random() Prerender Error

Next.js cacheComponents span-creation exemption is applied after instrumentation.register() returns, but @vercel/otel FetchInstrumentation captures a concrete Tracer during register(); subsequent outgoing HTTP requests in prerender create spans through that unpatched tracer and trip the sync-IO guard, producing a Math.random() prerender error.

highConfidence 89%Next.jsAffected V16.3.6Affected V16.3.8Affected V16.4.0-Canary.54

Origin Analysis

The `extendTracerProviderForCacheComponents` patch is only applied in `afterRegistration()`, after `instrumentation.register()` has already run. `@vercel/otel`'s `FetchInstrumentation` calls `tracerProvider.getTracer('@vercel/otel/fetch', …)` during `register()` and closes over the returned concrete `Tracer`. Because the global provider's delegate is set by then, the returned tracer is the real SDK tracer, not a ProxyTracer, and never passes through the patched methods. Later span creation for outgoing HTTP requests uses that concrete tracer, bypassing the sync-IO exemption and hitting `Math.random()` inside `RandomIdGenerator.generateSpanId`.
1. Use a Next.js app with cacheComponents and instrumentation.ts that calls registerOTel({ serviceName: 'repro' }) from @vercel/otel. 2. Create a page with a 'use cache' function that awaits searchParams then makes an outbound https.request (e.g., via stripe). 3. Run next dev and curl the page. 4. Observe error 'Next.js encountered the unstable value Math.random() while prerendering.'

Fixing Code Block

Edge Case Audit

Double-patching may occur if the existing `afterRegistration` call remains; ensure `extendTracerProviderForCacheComponents` is idempotent (e.g., guard with a symbol on the provider) or remove the afterRegistration call. Multiple calls to `setGlobalTracerProvider` (e.g., by different instrumentations) will each be patched; if a provider is replaced after a tracer was already captured, that tracer remains unpatched. Also, some OTel API implementations may not allow overriding `setGlobalTracerProvider` after the global provider has been set; this wrapper should be installed before any registration. Test on Node 18/20/24 and with common instrumentations. Rollback: remove the wrapper and restore original `setGlobalTracerProvider` before deploying.

Ecosystem Topology