Skip to content

fix(vercelai): Avoid double-capturing v4 tool errors in orchestrion mode - #22293

Merged
isaacs merged 3 commits into
developfrom
fix/vercelai-tool-error-express-flake
Jul 16, 2026
Merged

fix(vercelai): Avoid double-capturing v4 tool errors in orchestrion mode#22293
isaacs merged 3 commits into
developfrom
fix/vercelai-tool-error-express-flake

Conversation

@mydea

@mydeamydea commented Jul 15, 2026

Copy link
Copy Markdown
Member

In orchestrion mode, a v4 Vercel AI tool error was reported to Sentry twice: once by the channel subscriber (captureToolError, which captured the raw error mid-execution) and again when the SDK's wrapped AI_ToolExecutionError bubbled up to the app's error handling (express handler, or the global unhandled-rejection handler). The two events are different objects (raw error vs. wrapper), so Sentry's already-captured dedup didn't collapse them.

This also caused a flaky test: captures error in tool in express server used .unordered() with a single event expect and matched whichever of the two error envelopes arrived first — when the express-handler envelope won the race, the tool-tag assertions failed.

Root cause

The channel subscriber's tool-execute wrapper always captured the thrown error and re-threw. That capture is required on v5, where executeTools swallows the rejection into tool-error content so it never surfaces otherwise. On v4 the rejection instead bubbles out of the ai call, so it is already captured by the app's error handling — making the channel capture a duplicate. The OTel integration never had this problem because it doesn't self-capture v4 thrown tool errors; it lets them bubble.

Changes:

  • The orchestrion subscriber now only self-captures tool errors when the enclosing operation swallows them (v5+, detected via the 'v1' model spec version already used elsewhere in the file). On v4 it marks the tool span as errored and lets the error bubble, matching the OTel path — so a single error event is reported.
  • To preserve trace correlation for bubbled errors, the subscriber stamps the operation's call-site span onto the error via _sentry_active_span, reusing the exact mechanism the OTel integration already uses (onunhandledrejection restores it at capture time). Without this, an unhandled rejection in a non-OTel (orchestrion) process would start its own trace instead of correlating to the transaction.
  • Both of the above are per-operation facts keyed by the operation span, so they're stored together in a single WeakMap<Span, OperationErrorInfo> ({ callSiteSpan, toolErrorsBubbleToCaller }) written once at operation start, rather than two parallel collections.
  • Tests updated: both v4 error-in-tool scenarios now assert a single AI_ToolExecutionError event correlated to the transaction, in both orchestrion and OTel modes.

Fixes the flaky suites/tracing/vercelai/test.ts > ... > captures error in tool in express server [cjs].

mydeaand others added 2 commits July 15, 2026 14:49
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mydeamydea changed the title test(node): Fix flaky vercelai tool-error express testfix(vercelai): Avoid double-capturing v4 tool errors in orchestrion modeJul 15, 2026
@github-actions

github-actionsBot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser27.67 kB--
@sentry/browser - with treeshaking flags26.12 kB--
@sentry/browser (incl. Tracing)46.44 kB--
@sentry/browser (incl. Tracing + Span Streaming)48.23 kB--
@sentry/browser (incl. Tracing, Profiling)51.23 kB--
@sentry/browser (incl. Tracing, Replay)85.69 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags75.33 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)90.41 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)103.07 kB--
@sentry/browser (incl. Feedback)44.85 kB--
@sentry/browser (incl. sendFeedback)32.47 kB--
@sentry/browser (incl. FeedbackAsync)37.6 kB--
@sentry/browser (incl. Metrics)28.77 kB--
@sentry/browser (incl. Logs)29 kB--
@sentry/browser (incl. Metrics & Logs)29.68 kB--
@sentry/react29.48 kB--
@sentry/react (incl. Tracing)48.7 kB--
@sentry/vue33.1 kB--
@sentry/vue (incl. Tracing)48.42 kB--
@sentry/svelte27.7 kB--
CDN Bundle30.07 kB--
CDN Bundle (incl. Tracing)48.43 kB--
CDN Bundle (incl. Logs, Metrics)31.65 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.73 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.89 kB--
CDN Bundle (incl. Tracing, Replay)85.93 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)87.23 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.72 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.98 kB--
CDN Bundle - uncompressed89.7 kB--
CDN Bundle (incl. Tracing) - uncompressed146.45 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.4 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed150.42 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed219.13 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed265.65 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed269.61 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed279.35 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed283.3 kB--
@sentry/nextjs (client)51.25 kB--
@sentry/sveltekit (client)46.88 kB--
@sentry/core/server78.54 kB--
@sentry/core/browser64.89 kB--
@sentry/node-core62.83 kB--
@sentry/node125.25 kB--
@sentry/node (incl. diagnostics channel injection)140.37 kB+0.07%+95 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.96 kB--
@sentry/node/light50.84 kB--
@sentry/node - without tracing74.21 kB--
@sentry/aws-serverless83.42 kB+0.01%+4 B 🔺
@sentry/cloudflare (withSentry) - minified181.91 kB--
@sentry/cloudflare (withSentry)450.25 kB--

View base workflow run

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mydea
mydea marked this pull request as ready for review July 15, 2026 14:03
@mydea
mydea requested review from a team as code ownersJuly 15, 2026 14:03
@mydea
mydea requested review from JPeer264, andreiborza and isaacs and removed request for a teamJuly 15, 2026 14:03

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Clearly correct, brings this into alignment with the existing OTel behavior. 👍

@isaacs
isaacs merged commit 38d0d7b into developJul 16, 2026
312 checks passed
@isaacs
isaacs deleted the fix/vercelai-tool-error-express-flake branch July 16, 2026 16:44
Sign up for freeto 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.

2 participants

@mydea@isaacs