Skip to content

feat(core): Add refs field to Scope for non-serialized references - #23236

Open
mydea wants to merge 2 commits into
developfrom
feat/scope-refs-field
Open

feat(core): Add refs field to Scope for non-serialized references#23236
mydea wants to merge 2 commits into
developfrom
feat/scope-refs-field

Conversation

@mydea

@mydea mydea commented Aug 10, 2026

Copy link
Copy Markdown
Member

Adds a refs field to Scope — a shared bag for object references that are associated with a scope but must not be serialized (the active span in core, the OpenTelemetry Context in the opentelemetry package). refs is cloned as-is (shallow) in Scope.clone().

Root cause

The active span and the OTel context were stored in two separate, ad-hoc non-enumerable fields (_sentrySpan and _scopeContext). Scope.clone() only knew about the core span field and explicitly re-set it on the clone; it had no knowledge of the opentelemetry-owned _scopeContext. As a result, cloning a scope under OTel dropped the context reference, so getActiveSpan(clonedScope) — which reads the span out of the context attached to the scope — resolved to undefined. The two implementations disagreed on whether a clone preserved the active span.

Consolidating both references into a single refs object that clone() copies wholesale removes that asymmetry: a cloned scope now retains its span (core) and its context (OTel) uniformly.

This also allows us to remove some span/scope specifics from the scope class to keep this more generic. the scope class will simply clone/reset refs, whatever they may be.

Notable decisions:

  • refs is stored as a non-enumerable property (via addNonEnumerableProperty), matching the previous behavior of _sentrySpan/_scopeContext. This keeps it out of toEqual, Object.keys, toJSON, and event serialization — an enumerable field would otherwise leak the active span into structural comparisons and serialized payloads.
  • clone() does a shallow spread ({ ...this.refs }), consistent with how the other reference-holding scope fields are copied.
  • clear() resets refs to {}, replacing the previous per-field span reset.

The existing MaybeWeakRef wrapping is preserved for both the span and the context, so the GC/circular-reference protections are unchanged.

Store the active span (core) and OpenTelemetry context (opentelemetry) in a
shared, non-enumerable `refs` bag on the scope, and clone it in `clone()`.

This makes the span/context references survive `scope.clone()` consistently
across both the core and OpenTelemetry implementations. Previously the OTel
context lived in a separate `_scopeContext` field that `clone()` did not copy,
so `getActiveSpan(clonedScope)` returned `undefined` under OTel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 58d67a2. Configure here.


const clonedScope = scope.clone();
expect(getContextFromScope(clonedScope)).toBe(context);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feat PR lacks integration test

Medium Severity

Flagging this because it was mentioned in the PR review rules. This is a feat PR, but the diff only adds a unit test for clone preserving context. There is no integration or E2E coverage of the OTel scope-clone path that originally dropped the active span/context.

Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 58d67a2. Configure here.

Comment thread packages/core/src/scope.ts Outdated
setContextOnScope(scope, context);

// The _scopeContext property should not appear in Object.keys
expect(Object.keys(scope)).not.toContain('_scopeContext');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-enumerable refs untested

Low Severity

Flagging this because it was mentioned in the PR review rules. The old test asserted that context storage was non-enumerable; it was replaced with a check that only re-reads the context. Nothing now verifies that refs stays out of Object.keys / structural comparisons, despite that being a stated design goal.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 58d67a2. Configure here.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 30.3 kB -0.18% -52 B 🔽
@sentry/browser - with treeshaking flags 28.47 kB -0.17% -48 B 🔽
@sentry/browser - with treeshaking flags tracing without tracing 26.8 kB -0.18% -47 B 🔽
@sentry/browser (incl. Tracing) 48.63 kB +0.03% +13 B 🔺
@sentry/browser (incl. Tracing + Span Streaming) 48.64 kB +0.03% +14 B 🔺
@sentry/browser (incl. Tracing, Profiling) 53.48 kB +0.03% +14 B 🔺
@sentry/browser (incl. Tracing, Replay) 88.06 kB +0.02% +16 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.47 kB +0.02% +12 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 92.78 kB +0.02% +14 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 105.47 kB +0.02% +12 B 🔺
@sentry/browser (incl. Feedback) 47.62 kB -0.14% -64 B 🔽
@sentry/browser (incl. sendFeedback) 35.13 kB -0.15% -51 B 🔽
@sentry/browser (incl. FeedbackAsync) 40.27 kB -0.16% -64 B 🔽
@sentry/browser (incl. Metrics) 31.4 kB -0.07% -21 B 🔽
@sentry/browser (incl. Logs) 31.62 kB -0.11% -34 B 🔽
@sentry/browser (incl. Metrics & Logs) 32.31 kB -0.09% -28 B 🔽
@sentry/react 32.09 kB -0.16% -50 B 🔽
@sentry/react (incl. Tracing) 50.83 kB +0.02% +9 B 🔺
@sentry/vue 35.47 kB +0.05% +17 B 🔺
@sentry/vue (incl. Tracing) 50.6 kB +0.03% +13 B 🔺
@sentry/svelte 30.32 kB -0.2% -60 B 🔽
CDN Bundle 31.59 kB -0.06% -18 B 🔽
CDN Bundle (incl. Tracing) 48.92 kB +0.02% +7 B 🔺
CDN Bundle (incl. Logs, Metrics) 33.82 kB -0.07% -22 B 🔽
CDN Bundle (incl. Tracing, Logs, Metrics) 50.89 kB +0.02% +6 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 74.36 kB -0.03% -20 B 🔽
CDN Bundle (incl. Tracing, Replay) 86.5 kB +0.01% +7 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.4 kB +0.01% +7 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 92.22 kB +0.01% +7 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94.19 kB +0.01% +7 B 🔺
CDN Bundle - uncompressed 93.86 kB -0.1% -93 B 🔽
CDN Bundle (incl. Tracing) - uncompressed 146.95 kB +0.02% +28 B 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 100.32 kB -0.1% -93 B 🔽
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 152.81 kB +0.02% +28 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 229.25 kB -0.05% -93 B 🔽
CDN Bundle (incl. Tracing, Replay) - uncompressed 266.2 kB +0.02% +28 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 272.04 kB +0.02% +28 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 279.9 kB +0.02% +28 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 285.73 kB +0.01% +28 B 🔺
@sentry/nextjs (client) 53.39 kB +0.02% +10 B 🔺
@sentry/sveltekit (client) 49.04 kB +0.03% +13 B 🔺
@sentry/core/server 65.61 kB +0.02% +10 B 🔺
@sentry/core/browser 51.93 kB +0.02% +10 B 🔺
@sentry/node 118.47 kB +0.01% +8 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 0 B added added
@sentry/node - without tracing 82.57 kB +0.01% +7 B 🔺
@sentry/aws-serverless 91.95 kB +0.01% +8 B 🔺
@sentry/cloudflare (withSentry) - minified 214.73 kB +0.02% +28 B 🔺
@sentry/cloudflare (withSentry) 530.36 kB -0.01% -3 B 🔽

View base workflow run

@mydea
mydea marked this pull request as ready for review August 10, 2026 13:52
@mydea
mydea requested a review from a team as a code owner August 10, 2026 13:52
@mydea
mydea requested review from JPeer264, Lms24 and isaacs and removed request for a team August 10, 2026 13:52
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