Skip to content

fix(effect): Honor external parents and isolate root spans - #23900

Open
JPeer264 wants to merge 1 commit into
developfrom
jp/effect-sdk-trace-structure
Open

fix(effect): Honor external parents and isolate root spans#23900
JPeer264 wants to merge 1 commit into
developfrom
jp/effect-sdk-trace-structure

Conversation

@JPeer264

@JPeer264 JPeer264 commented Sep 2, 2026

Copy link
Copy Markdown
Member

@sentry/effect ignored Tracer.ExternalSpan parents and fell back to the active Sentry span. An incoming traceparent header on an Effect HTTP server or a persisted trace continued with Tracer.externalSpan therefore started a disconnected trace, and a root: true span or a span leaked from another fiber through the async context could become the parent of an unrelated span. On the server, every parentless span also shared the process-wide propagation context, so a long-lived process put all of its work into one trace.

  • An external parent now continues its trace as a new root span with the external span as parent_span_id. No dynamic sampling context is frozen, so the SDK builds one from the client.
  • A parentless span only nests under a foreign active Sentry span (an http.server span from the Node SDK, a pageload), never under a span this tracer created.
  • The server tracer starts a new trace for every parentless span, unless the user set up the current scope (continueTrace, withScope, an isolation scope). The client tracer keeps parentless spans in the page trace.

The effect-3-node and effect-4-node e2e apps cover an incoming traceparent header, a Tracer.externalSpan parent, and a root: true span inside a request.

@JPeer264 JPeer264 self-assigned this Sep 2, 2026
@JPeer264
JPeer264 requested a review from a team as a code owner September 2, 2026 07:09
@JPeer264
JPeer264 requested review from mydea and nicohrubec and removed request for a team September 2, 2026 07:09
@JPeer264
JPeer264 marked this pull request as draft September 2, 2026 07:09
`@sentry/effect` ignored `Tracer.ExternalSpan` parents and fell back to the
active Sentry span. An incoming `traceparent` header on an Effect HTTP server
or a persisted trace continued with `Tracer.externalSpan` therefore started a
disconnected trace, and a `root: true` span or a span leaked from another
fiber through the async context could become the parent of an unrelated span.
On the server, every parentless span also shared the process-wide propagation
context, so a long-lived process put all of its work into one trace.

- An external parent now continues its trace as a new root span with the
  external span as `parent_span_id`. No dynamic sampling context is frozen, so
  the SDK builds one from the client.
- A parentless span only nests under a foreign active Sentry span (an
  `http.server` span from the Node SDK, a pageload), never under a span this
  tracer created.
- The server tracer starts a new trace for every parentless span, unless the
  user set up the current scope (`continueTrace`, `withScope`, an isolation
  scope). The client tracer keeps parentless spans in the page trace.

These fixes apply to both trace lifecycles. One related limitation stays and
is specific to `traceLifecycle: 'static'`: a child span that ends after its
root span is dropped with the transaction. Long-running Effect fibers, such as
a background agent that outlives the request that started it, lose those
children unless `traceLifecycle: 'stream'` is used, which sends every span on
its own end and is the default since v11.

The effect-3-node and effect-4-node e2e apps cover an incoming traceparent
header, a `Tracer.externalSpan` parent, and a `root: true` span inside a
request.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@JPeer264
JPeer264 force-pushed the jp/effect-sdk-trace-structure branch from 07eefa2 to 61b80c5 Compare September 2, 2026 07:30
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 28.57 kB - -
@sentry/browser - with treeshaking flags 26.94 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 26.83 kB - -
@sentry/browser (incl. Tracing) 48.87 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 48.88 kB - -
@sentry/browser (incl. Tracing, Profiling) 51.8 kB - -
@sentry/browser (incl. Tracing, Replay) 88.36 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.76 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 93.05 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 106.02 kB - -
@sentry/browser (incl. Feedback) 46.06 kB - -
@sentry/browser (incl. sendFeedback) 33.64 kB - -
@sentry/browser (incl. FeedbackAsync) 38.74 kB - -
@sentry/browser (incl. Metrics) 29.52 kB - -
@sentry/browser (incl. Logs) 29.81 kB - -
@sentry/browser (incl. Metrics & Logs) 30.45 kB - -
@sentry/react 30.32 kB - -
@sentry/react (incl. Tracing) 51.08 kB - -
@sentry/vue 35.74 kB - -
@sentry/vue (incl. Tracing) 51.14 kB - -
@sentry/svelte 28.6 kB - -
CDN Bundle 30.36 kB - -
CDN Bundle (incl. Tracing) 49.52 kB - -
CDN Bundle (incl. Logs, Metrics) 32.59 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 51.43 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.19 kB - -
CDN Bundle (incl. Tracing, Replay) 87.01 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.88 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 92.94 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94.84 kB - -
CDN Bundle - uncompressed 89.97 kB - -
CDN Bundle (incl. Tracing) - uncompressed 147.58 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 96.27 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 153.27 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 225.43 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 267.07 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 272.75 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 280.77 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 286.44 kB - -
@sentry/nextjs (client) 53.7 kB - -
@sentry/sveltekit (client) 49.3 kB - -
@sentry/core/server 40.74 kB - -
@sentry/core/browser 13.42 kB - -
@sentry/node 123.87 kB +0.02% +19 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 81.4 kB - -
@sentry/node - without tracing 88.2 kB +0.03% +22 B 🔺
@sentry/node - without channel injection 103.3 kB +0.02% +15 B 🔺
@sentry/aws-serverless 96.56 kB +0.03% +21 B 🔺
@sentry/cloudflare (withSentry) - minified 201.23 kB - -
@sentry/cloudflare (withSentry) 500.94 kB - -

View base workflow run

@JPeer264
JPeer264 marked this pull request as ready for review September 2, 2026 07:43
@JPeer264
JPeer264 requested review from Lms24 and s1gr1d September 2, 2026 07:43
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

👋 @Lms24, @s1gr1d — Please review this PR when you get a chance!

@JPeer264
JPeer264 requested a review from nicohrubec September 7, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant