Skip to content

fix(core): Return same value from startSpan as callback returns#19300

Merged
isaacs merged 7 commits intodevelopfrom
sig/promise-startspan-types
Mar 19, 2026
Merged

fix(core): Return same value from startSpan as callback returns#19300
isaacs merged 7 commits intodevelopfrom
sig/promise-startspan-types

Conversation

@s1gr1d
Copy link
Copy Markdown
Member

@s1gr1d s1gr1d commented Feb 12, 2026

When using startSpan, .then() is called on the callback's return value. This creates another Promise which is a problem in for example jQuery, where the returned Promise does not have the same methods as the jqXHR object.

Closes #19242

@s1gr1d s1gr1d requested a review from isaacs February 12, 2026 14:38
Comment thread dev-packages/browser-integration-tests/package.json Outdated
Comment thread packages/core/src/asyncContext/stackStrategy.ts Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 12, 2026

Codecov Results 📊


Generated by Codecov Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 12, 2026

size-limit report 📦

⚠️ Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

Path Size % Change Change
@sentry/browser 25.69 kB +0.2% +49 B 🔺
@sentry/browser - with treeshaking flags 24.17 kB +0.14% +33 B 🔺
@sentry/browser (incl. Tracing) 42.67 kB +0.13% +54 B 🔺
@sentry/browser (incl. Tracing, Profiling) 47.33 kB +0.12% +55 B 🔺
@sentry/browser (incl. Tracing, Replay) 81.47 kB +0.07% +50 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 71.06 kB +0.09% +60 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 86.17 kB +0.05% +41 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 98.4 kB +0.03% +29 B 🔺
@sentry/browser (incl. Feedback) 42.48 kB +0.08% +30 B 🔺
@sentry/browser (incl. sendFeedback) 30.35 kB +0.15% +43 B 🔺
@sentry/browser (incl. FeedbackAsync) 35.4 kB +0.12% +39 B 🔺
@sentry/browser (incl. Metrics) 26.96 kB +0.15% +38 B 🔺
@sentry/browser (incl. Logs) 27.1 kB +0.12% +32 B 🔺
@sentry/browser (incl. Metrics & Logs) 27.78 kB +0.15% +39 B 🔺
@sentry/react 27.45 kB +0.22% +58 B 🔺
@sentry/react (incl. Tracing) 45.01 kB +0.14% +60 B 🔺
@sentry/vue 30.13 kB +0.16% +46 B 🔺
@sentry/vue (incl. Tracing) 44.52 kB +0.09% +39 B 🔺
@sentry/svelte 25.7 kB +0.16% +40 B 🔺
CDN Bundle 28.35 kB +0.27% +75 B 🔺
CDN Bundle (incl. Tracing) 43.57 kB +0.15% +62 B 🔺
CDN Bundle (incl. Logs, Metrics) 29.22 kB +0.27% +77 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) 44.43 kB +0.17% +75 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 68.28 kB +0.11% +74 B 🔺
CDN Bundle (incl. Tracing, Replay) 80.4 kB +0.08% +63 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 81.3 kB +0.09% +65 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 85.96 kB +0.11% +91 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 86.84 kB +0.09% +74 B 🔺
CDN Bundle - uncompressed 82.7 kB +0.1% +77 B 🔺
CDN Bundle (incl. Tracing) - uncompressed 128.62 kB +0.05% +64 B 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 85.57 kB +0.1% +77 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 131.49 kB +0.05% +64 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 209.2 kB +0.04% +77 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 245.48 kB +0.03% +64 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 248.33 kB +0.03% +64 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 258.39 kB +0.03% +64 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 261.23 kB +0.03% +64 B 🔺
@sentry/nextjs (client) 47.4 kB +0.08% +37 B 🔺
@sentry/sveltekit (client) 43.12 kB +0.12% +51 B 🔺
@sentry/node-core 56.42 kB +0.13% +73 B 🔺
@sentry/node 173.37 kB +0.13% +212 B 🔺
@sentry/node - without tracing 96.43 kB +0.1% +87 B 🔺
@sentry/aws-serverless 113.44 kB +0.09% +100 B 🔺

View base workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 12, 2026

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 9,532 - 11,324 -16%
GET With Sentry 1,704 18% 1,998 -15%
GET With Sentry (error only) 6,266 66% 7,342 -15%
POST Baseline 1,189 - 1,307 -9%
POST With Sentry 557 47% 660 -16%
POST With Sentry (error only) 1,018 86% 1,161 -12%
MYSQL Baseline 3,177 - 3,528 -10%
MYSQL With Sentry 350 11% 453 -23%
MYSQL With Sentry (error only) 2,592 82% 2,973 -13%

View base workflow run

@s1gr1d s1gr1d requested review from Lms24 February 12, 2026 15:00
Copy link
Copy Markdown

@cursor cursor bot left a comment

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 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Comment thread packages/core/src/utils/handleCallbackErrors.ts Outdated
@isaacs isaacs marked this pull request as draft February 13, 2026 15:27
@isaacs
Copy link
Copy Markdown
Member

isaacs commented Feb 13, 2026

Converting to a draft, going to push some more commits to try out a slightly different approach to this.

The Remix failures are interesting. Playwright timing out is less interesting, but also could be indicative of a problem, if it's waiting for an expected failure that we're swallowing (haven't dug deeply into it yet).

@isaacs isaacs force-pushed the sig/promise-startspan-types branch from 58c695d to a729eb8 Compare February 16, 2026 00:38
@isaacs
Copy link
Copy Markdown
Member

isaacs commented Feb 16, 2026

So, there is no way to return the actual promise and also track the error, without obscuring the unhandledrejection behavior (either suppressing it on unhandled rejections, or triggering it on handled ones).

Added a commit to copy any new properties that exist on the original promise, onto the chained one. If the property is a function, then a wrapper function is added that calls the original method, bound to the original object.

This does still have the slight gotcha that any add-on methods on the original promise are now bound to it. So, this might be surprising:

const original = getDecoratedPromiseSomehow();
const returned = startSpan({..}, () => original);
const newObject = {};
returned.addedMethod.call(newObject); // surprise! runs in this-context of `original`

We can detect this and work around it easily enough if needed, but I'm thinking this is already probably more than enough support for this edge case, and if we're going any further, sniffing the this context, it seems like we'd be best off just biting the bullet with a Proxy.

Will check back in a bit to see what CI thinks of this.

Comment thread packages/core/src/utils/handleCallbackErrors.ts Outdated
Comment thread packages/core/src/asyncContext/stackStrategy.ts
Comment thread packages/core/src/utils/chain-and-copy-promiselike.ts
@isaacs isaacs force-pushed the sig/promise-startspan-types branch from a729eb8 to 77f8f02 Compare March 19, 2026 16:39
@isaacs isaacs marked this pull request as ready for review March 19, 2026 16:40
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 19, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Deps

  • Bump mongodb-memory-server-global from 10.1.4 to 11.0.1 by dependabot in #19888
  • Bump stacktrace-parser from 0.1.10 to 0.1.11 by dependabot in #19887

Bug Fixes 🐛

  • (core) Return same value from startSpan as callback returns by s1gr1d in #19300
  • (deps) Bump socket.io-parser to 4.2.6 to fix CVE-2026-33151 by chargome in #19880
  • (nestjs) Add node to nest metadata by chargome in #19875
  • (serverless) Add node to metadata by nicohrubec in #19878

Internal Changes 🔧

  • (astro) Re-enable server island tracing e2e test in Astro 6 by Lms24 in #19872
  • (node-integration-tests) Remove unnecessary file-type dependency by Lms24 in #19824

🤖 This preview updates automatically when you update the PR.

@isaacs isaacs marked this pull request as draft March 19, 2026 16:57
@isaacs isaacs force-pushed the sig/promise-startspan-types branch 3 times, most recently from cf08b2f to 44ae312 Compare March 19, 2026 17:34
s1gr1d and others added 7 commits March 19, 2026 11:13
Copy properties from the original promise onto the chained tracker, so
that we can return something that can inspect the error, does not
obscure `unhandledrejection`, *and* supports jQuery's extended
PromiseLike objects.

We only do this if the original PromiseLike object or its chained
counterpart are not `instanceof Promise`. So far, we have not
encountered such decoration on "normal" Promise objects, so this is a
fast way to ensure that we're only providing this affordance where it's
needed. This does introduce a limitation that if someone decorates a
standard Promise object, and its decorations do not extend to chained
results of `then()`, then we will lose them. If and when that happens,
we can consider extending this check to something more thorough, even if
it's slightly less performant.

A guard is added to prevent cases where a chained/copied promise is
passed through this function again, so that we know we still have to do
the operation even though it's a "normal" Promise.
@isaacs isaacs force-pushed the sig/promise-startspan-types branch from 44ae312 to 9b8d764 Compare March 19, 2026 18:13
@s1gr1d s1gr1d marked this pull request as ready for review March 19, 2026 18:39
@s1gr1d
Copy link
Copy Markdown
Member Author

s1gr1d commented Mar 19, 2026

@isaacs took over this PR, so I cannot approve it "officially" in the UI on GitHub but looks good to me 👍

@isaacs isaacs self-requested a review March 19, 2026 18:53
Copy link
Copy Markdown
Member

@isaacs isaacs left a comment

Choose a reason for hiding this comment

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

I'm not actually the one reviewing this, because I took it over, but posting a positive 👍 so GitHub knows @s1gr1d approved it.

@isaacs isaacs merged commit 5e99593 into develop Mar 19, 2026
460 of 463 checks passed
@isaacs isaacs deleted the sig/promise-startspan-types branch March 19, 2026 19:23
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.

startSpan/startSpanManual wraps promise-like objects in a way that’s not reflected by the TypeScript type

2 participants