66 _INTERNAL_setSpanForScope ,
77 _INTERNAL_startInactiveSpan ,
88 addChildSpanToSpan ,
9+ getCapturedScopesOnSpan ,
910 getCurrentScope ,
1011 getDynamicSamplingContextFromSpan ,
1112 getIsolationScope ,
@@ -18,6 +19,7 @@ import {
1819} from '@sentry/core' ;
1920import type { Span , SpanAttributes , SpanLink } from '@sentry/core' ;
2021import { applyOtelSpanData , applyOtelSpanKind } from './applyOtelSpanData' ;
22+ import { SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY } from './constants' ;
2123import { getSamplingDecision } from './utils/getSamplingDecision' ;
2224
2325export class SentryTracer implements Tracer {
@@ -66,7 +68,15 @@ export class SentryTracer implements Tracer {
6668 ) as F ;
6769
6870 const span = this . startSpan ( name , options , ctx ) ;
69- const ctxWithSpan = trace . setSpan ( ctx , span ) ;
71+ let ctxWithSpan = trace . setSpan ( ctx , span ) ;
72+
73+ // Run the span's callback under the isolation scope captured when the span was created, so scope state
74+ // used or set during the span (tags, breadcrumbs, captured errors) belongs to that span and stays
75+ // isolated from other concurrent work. Without this it can land on a different isolation scope.
76+ const capturedIsolationScope = getCapturedScopesOnSpan ( span as unknown as Span ) . isolationScope ;
77+ if ( capturedIsolationScope ) {
78+ ctxWithSpan = ctxWithSpan . setValue ( SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY , capturedIsolationScope ) ;
79+ }
7080
7181 return context . with ( ctxWithSpan , ( ) => {
7282 _INTERNAL_setSpanForScope ( getCurrentScope ( ) , span as unknown as Span ) ;
0 commit comments