Repository navigation
fix(server-utils): Mark AI spans as cancelled when the caller aborts - #26297
Merged
Merged
Conversation
A caller's abort before the response arrived, or on a non-streaming call, was recorded as an error on the OpenAI, Anthropic and Google GenAI spans. It is now `cancelled`, matching what Google GenAI and Bedrock already record for an abort mid-stream. A caller's own `AbortSignal.timeout()` stays an error. Also removes the duplicate `'end'` listener on Anthropic's MessageStream. Refs #26130 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generic already declares `aborted`, so the cast left over from the duplicate `'end'` listener isn't needed. Co-Authored-By: Rola Abuhasna <rola.abuhasna@sentry.io>
Contributor
size-limit report 📦Compared: a9ef3cb (PR test merge using develop at c7d73e4) Against: c7d73e4 (develop) · base run #66026 ✅ Baseline matches: this diff contains only this PR's changes.
|
Contributor
Optional E2E testsSome optional checks were not successful. They do not block the merge. 4 not successful, 54 successful. See the run.
Successful checks
|
…tream() as an error `stream.aborted` is set for any abort of the caller's signal, so a timeout was recorded as `cancelled`. The 'end' listener now reads the caller's signal, the same check `messages.create()` uses. An abort with no signal, like `stream.abort()`, stays `cancelled`. Co-Authored-By: Rola Abuhasna <rola.abuhasna@sentry.io>
RulaKhaled
marked this pull request as ready for review
November 12, 2026 12:07
javascript-sdk-gitflow
Bot
requested review from
JPeer264,
andreiborza and
isaacs
November 12, 2026 12:07
…t-status # Conflicts: # packages/server-utils/src/integrations/anthropic.ts # packages/server-utils/src/integrations/aws-sdk/services/bedrock-runtime.ts # packages/server-utils/src/integrations/openai.ts
There was a problem hiding this comment.
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.
Reviewed by Cursor Bugbot for commit bb996a5. Configure here.
A thread stream sends each `create()` with its own controller signal, which doesn't carry the reason the caller's signal fired with. Keep the caller's signal from `_start()` so an `AbortSignal.timeout()` on a thread stream is an error, like on `messages.stream()`.
…t-status # Conflicts: # packages/server-utils/src/integrations/aws-sdk/services/bedrock-runtime.ts
andreiborza
approved these changes
Nov 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why: If the caller aborts an OpenAI, Anthropic or Google GenAI call before the response arrives, or aborts a non-streaming call, the span is recorded as
internal_error. The same abort mid-stream is alreadycancelledon Google GenAI and Bedrock. These calls now recordcancelledon both the client-wrapper path and the Orchestrion path. We check the signal, not the error name, because SDK timeouts also throw anAbortError. A caller's ownAbortSignal.timeout()also stays an error: it's a timeout, and under span streamingcancelledis sent asok.Anthropic's
messages.stream()follows the same rule.stream.abortedis set for any abort of the caller's signal and doesn't say why, so its'end'listener now also reads the caller's signal. An abort with no signal (stream.abort(), or breaking out of the loop) stayscancelled. This also removes a duplicate'end'listener on Anthropic'sMessageStream, left over from two PRs merging into the same function.How to review: Start with
getErrorStatus/markCancelledIfAbortedinai/core/utils.ts. The provider changes are call sites. The new OpenAI and Anthropicscenario-abortintegration tests fail ondevelopand pass here.Refs #26130. This covers the pre-stream item. Checking the signal after the loop for OpenAI/Anthropic mid-stream, and
cancel()on Mistral and Workers AI, are still open there.via Rola Abuhasna.
--
View Session [Sentry]