diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/slow-stream/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/slow-stream/page.tsx
new file mode 100644
index 000000000000..478ac04626a6
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/app/slow-stream/page.tsx
@@ -0,0 +1,20 @@
+import { headers } from 'next/headers';
+import { Suspense } from 'react';
+
+// Above the pageload's 10 second wait for the trace meta tag, but short enough that the tag still
+// arrives before the pageload ends.
+const DELAY_MS = 10_500;
+
+async function SlowContent() {
+ await headers();
+ await new Promise(resolve => setTimeout(resolve, DELAY_MS));
+ return
Slow content
;
+}
+
+export default function Page() {
+ return (
+ Loading...}>
+
+
+ );
+}
diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/tests/cacheOrigin-pageloadConnection.spec.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/tests/cacheOrigin-pageloadConnection.spec.ts
index f06c4da961cd..36efdae23642 100644
--- a/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/tests/cacheOrigin-pageloadConnection.spec.ts
+++ b/dev-packages/e2e-tests/test-applications/nextjs-16-cacheComponents/tests/cacheOrigin-pageloadConnection.spec.ts
@@ -212,3 +212,33 @@ test('keeps a navigation that starts while the pageload waits for the trace meta
expect(pageloadTx.contexts?.trace?.data?.['sentry.idle_span_finish_reason']).toBe('cancelled');
expect(navigationTx.contexts?.trace?.data?.['sentry.idle_span_finish_reason']).toBe('idleTimeout');
});
+
+test('links the server request when its trace meta tag arrives after the pageload stopped waiting', async ({
+ page,
+}) => {
+ test.skip(process.env.TEST_ENV !== 'production', 'Only a prerendered shell makes the trace meta tag arrive late');
+ test.setTimeout(60_000);
+
+ const pageloadTxPromise = waitForTransaction(APP, transactionEvent => {
+ return transactionEvent.transaction === '/slow-stream' && transactionEvent.contexts?.trace?.op === 'pageload';
+ });
+
+ await page.goto('/slow-stream', { waitUntil: 'commit' });
+ await expect(page.locator('#slow-content')).toBeVisible({ timeout: 20_000 });
+ const [requestTraceId, requestSpanId] = (await page
+ .locator('meta[name="sentry-trace"]')
+ .getAttribute('content'))!.split('-');
+
+ const pageloadTx = await pageloadTxPromise;
+
+ // The tag arrived after the pageload had started its own trace, so the pageload only links it.
+ expect(pageloadTx.contexts?.trace?.trace_id).not.toBe(requestTraceId);
+ expect(pageloadTx.contexts?.trace?.links).toEqual([
+ {
+ trace_id: requestTraceId,
+ span_id: requestSpanId,
+ sampled: true,
+ attributes: { [SENTRY_LINK_TYPE]: 'server_request' },
+ },
+ ]);
+});
diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming-cacheComponents/app/slow-stream/page.tsx b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming-cacheComponents/app/slow-stream/page.tsx
new file mode 100644
index 000000000000..478ac04626a6
--- /dev/null
+++ b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming-cacheComponents/app/slow-stream/page.tsx
@@ -0,0 +1,20 @@
+import { headers } from 'next/headers';
+import { Suspense } from 'react';
+
+// Above the pageload's 10 second wait for the trace meta tag, but short enough that the tag still
+// arrives before the pageload ends.
+const DELAY_MS = 10_500;
+
+async function SlowContent() {
+ await headers();
+ await new Promise(resolve => setTimeout(resolve, DELAY_MS));
+ return Slow content
;
+}
+
+export default function Page() {
+ return (
+ Loading...}>
+
+
+ );
+}
diff --git a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming-cacheComponents/tests/cacheOrigin-pageloadConnection.spec.ts b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming-cacheComponents/tests/cacheOrigin-pageloadConnection.spec.ts
index 3d1512789f82..b5eadf749de5 100644
--- a/dev-packages/e2e-tests/test-applications/nextjs-16-streaming-cacheComponents/tests/cacheOrigin-pageloadConnection.spec.ts
+++ b/dev-packages/e2e-tests/test-applications/nextjs-16-streaming-cacheComponents/tests/cacheOrigin-pageloadConnection.spec.ts
@@ -211,3 +211,33 @@ test('keeps a navigation that starts while the pageload waits for the trace meta
value: 'idleTimeout',
});
});
+
+test('links the server request when its trace meta tag arrives after the pageload stopped waiting', async ({
+ page,
+}) => {
+ test.skip(process.env.TEST_ENV !== 'production', 'Only a prerendered shell makes the trace meta tag arrive late');
+ test.setTimeout(60_000);
+
+ const pageloadSpanPromise = waitForStreamedSpan(APP, span => {
+ return span.name === '/slow-stream' && getSpanOp(span) === 'pageload' && span.is_segment;
+ });
+
+ await page.goto('/slow-stream', { waitUntil: 'commit' });
+ await expect(page.locator('#slow-content')).toBeVisible({ timeout: 20_000 });
+ const [requestTraceId, requestSpanId] = (await page
+ .locator('meta[name="sentry-trace"]')
+ .getAttribute('content'))!.split('-');
+
+ const pageloadSpan = await pageloadSpanPromise;
+
+ // The tag arrived after the pageload had started its own trace, so the pageload only links it.
+ expect(pageloadSpan.trace_id).not.toBe(requestTraceId);
+ expect(pageloadSpan.links).toEqual([
+ {
+ trace_id: requestTraceId,
+ span_id: requestSpanId,
+ sampled: true,
+ attributes: { [SENTRY_LINK_TYPE]: { type: 'string', value: 'server_request' } },
+ },
+ ]);
+});