From 2f4c52a42d741e242acee0086f2bf03343836093 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 11 Aug 2026 10:41:59 +0200 Subject: [PATCH 1/4] ref(core): Streamline how active spans are set in core --- packages/core/src/tracing/trace.ts | 60 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index f10583f301b7..b7a7902a7a08 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -88,22 +88,13 @@ export function startSpan(options: StartSpanOptions, callback: (span: Span) = // Ignored root spans still need to be set on scope so that `getActiveSpan()` returns them // and descendants are also non-recording. Ignored child spans don't need this because // the parent span is already on scope. - if (!spanIsIgnored(activeSpan) || !parentSpan) { - _setSpanForScope(scope, activeSpan); - } + const makeSpanActive = !spanIsIgnored(activeSpan) || !parentSpan; - return handleCallbackErrors( + return runCallback( + activeSpan, + makeSpanActive, () => callback(activeSpan), - () => { - // Only update the span status if it hasn't been changed yet, and the span is not yet finished - const { status } = spanToJSON(activeSpan); - if (activeSpan.isRecording() && status === 'ok') { - activeSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' }); - } - }, - () => { - activeSpan.end(); - }, + () => activeSpan.end(), ); }); }); @@ -150,24 +141,13 @@ export function startSpanManual(options: StartSpanOptions, callback: (span: S // We don't set ignored child spans onto the scope because there likely is an active, // unignored span on the scope already. - if (!spanIsIgnored(activeSpan) || !parentSpan) { - _setSpanForScope(scope, activeSpan); - } + const makeSpanActive = !spanIsIgnored(activeSpan) || !parentSpan; - return handleCallbackErrors( - // We pass the `finish` function to the callback, so the user can finish the span manually - // this is mainly here for historic purposes because previously, we instructed users to call - // `finish` instead of `span.end()` to also clean up the scope. Nowadays, calling `span.end()` - // or `finish` has the same effect and we simply leave it here to avoid breaking user code. - () => callback(activeSpan, () => activeSpan.end()), - () => { - // Only update the span status if it hasn't been changed yet, and the span is not yet finished - const { status } = spanToJSON(activeSpan); - if (activeSpan.isRecording() && status === 'ok') { - activeSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' }); - } - }, - ); + // We pass the `finish` function to the callback, so the user can finish the span manually + // this is mainly here for historic purposes because previously, we instructed users to call + // `finish` instead of `span.end()` to also clean up the scope. Nowadays, calling `span.end()` + // or `finish` has the same effect and we simply leave it here to avoid breaking user code. + return runCallback(activeSpan, makeSpanActive, () => callback(activeSpan, () => activeSpan.end())); }); }); } @@ -677,3 +657,21 @@ function _shouldIgnoreStreamedSpan(client: Client | undefined, spanArguments: Se export function spanIsIgnored(span: Span): span is SentryNonRecordingSpan { return spanIsNonRecordingSpan(span) && span.dropReason === 'ignored'; } + +function runCallback(span: Span, makeSpanActive: boolean, callback: () => T, finallyCallback?: () => void): T { + const wrapper = makeSpanActive ? (callback: () => T) => withActiveSpan(span, callback) : callback; + + return wrapper(() => + handleCallbackErrors( + () => callback(), + () => { + // Only update the span status if it hasn't been changed yet, and the span is not yet finished + const { status } = spanToJSON(span); + if (span.isRecording() && status === 'ok') { + span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' }); + } + }, + finallyCallback, + ), + ); +} From c56c703a984faff55549cd32d4b27f242ec319f1 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 11 Aug 2026 10:48:17 +0200 Subject: [PATCH 2/4] fix it --- packages/core/src/tracing/trace.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index b7a7902a7a08..a0494d6d29ed 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -659,7 +659,9 @@ export function spanIsIgnored(span: Span): span is SentryNonRecordingSpan { } function runCallback(span: Span, makeSpanActive: boolean, callback: () => T, finallyCallback?: () => void): T { - const wrapper = makeSpanActive ? (callback: () => T) => withActiveSpan(span, callback) : callback; + const wrapper = makeSpanActive + ? (callback: () => T) => withActiveSpan(span, callback) + : (callback: () => T) => callback(); return wrapper(() => handleCallbackErrors( From 76f8cc5757b846117d8bd30ca67f7a32e06c8a34 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 11 Aug 2026 10:56:33 +0200 Subject: [PATCH 3/4] fix span on scope setting --- packages/core/src/tracing/trace.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index a0494d6d29ed..4930c322dc98 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -660,7 +660,13 @@ export function spanIsIgnored(span: Span): span is SentryNonRecordingSpan { function runCallback(span: Span, makeSpanActive: boolean, callback: () => T, finallyCallback?: () => void): T { const wrapper = makeSpanActive - ? (callback: () => T) => withActiveSpan(span, callback) + ? (callback: () => T) => { + return withActiveSpan(span, () => { + // Make sure the correct scope is captured on the span + setCapturedScopesOnSpan(span, getCurrentScope(), getIsolationScope()); + return callback(); + }); + } : (callback: () => T) => callback(); return wrapper(() => From e2e5f4dfb2419c50e4bdf27015b96444ff8eb2a7 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 11 Aug 2026 10:57:24 +0200 Subject: [PATCH 4/4] better comment --- packages/core/src/tracing/trace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index 4930c322dc98..2e0b4e148d2f 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -662,7 +662,7 @@ function runCallback(span: Span, makeSpanActive: boolean, callback: () => T, const wrapper = makeSpanActive ? (callback: () => T) => { return withActiveSpan(span, () => { - // Make sure the correct scope is captured on the span + // Make sure the correct scope is captured on the span, since withActiveSpan forks the scope setCapturedScopesOnSpan(span, getCurrentScope(), getIsolationScope()); return callback(); });