Repository navigation
fix(openai): finish streaming gen_ai span on early stream close - #7852
intertermux-code wants to merge 1 commit into
Conversation
The four streaming chunk iterators only finished the gen_ai.chat / gen_ai.responses span in the code after their iteration loop. Closing the stream early, leaving a `with` block after one chunk, or losing the connection skipped that code, so the span was never finished and got dropped from the transaction. Wrap the loop and post-loop bookkeeping in try/finally so the span is always finished (errored on connection errors), and patch Stream.close / AsyncStream.close to finish the span too, mirroring the Anthropic integration. The span is attached to the stream and detached on finish so it is finished exactly once no matter which path runs first. Fixes getsentry#7847.
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 d0064c6. Configure here.
| return | ||
| with capture_internal_exceptions(): | ||
| del stream._span # type: ignore[union-attr] | ||
| span.__exit__(*exc_info) |
There was a problem hiding this comment.
Leaked exceptions mark stream spans failed
Medium Severity
Finishing the stream span with sys.exc_info() records whatever exception is currently active, not what happened on the stream. GeneratorExit from an abandoned or broken-off iterator, and any exception the caller is already handling, both reach span.__exit__, so gen_ai.chat / gen_ai.responses spans are marked internal_error even when the stream succeeded or was closed on purpose.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit d0064c6. Configure here.


Description
Streaming chat-completions and Responses API calls lost their
gen_ai.chat/gen_ai.responsesspan whenever the stream wasn't read to the end: the four chunk iterators insentry_sdk/integrations/openai.pyonly finished the span in the code after theirforloop, so an earlystream.close(), leaving awithblock after one chunk, or a dropped connection skipped finalization and the transaction went out without the span.This ports the approach the Anthropic integration already uses: the loop and post-loop bookkeeping are wrapped in
try/finallyso the span is always finished (marked errored when the connection drops), andStream.close/AsyncStream.closeare patched to finish the span on early close. The span is attached to the stream object and detached on finish, so it is finished exactly once no matter which path runs first.Issues
Reminders
test_streaming_chat_completion_span_finished_on_early_exit, parametrized over break-then-close andwith-block early exit; both fail without the fix)ruff check/ruff format,mypyclean on the changed module