fix(anthropic): Patch Stream.close() and MessageStream.close() to finish spans
#5674
3 issues
Medium
AsyncStream.close() and AsyncMessageStream.close() not patched, spans may not finish - `sentry_sdk/integrations/anthropic.py:108-123`
The PR patches Stream.close() and conditionally MessageStream.close() to finish spans when the connection is closed early, but does not patch the corresponding AsyncStream.close() or AsyncMessageStream.close() methods. If a user calls close() on an async stream before fully consuming the iterator, the span will not be finished properly, leaving orphaned spans. This creates inconsistent behavior between sync and async APIs.
Missing capture_internal_exceptions() around _finish_streaming_span in _wrap_close - `sentry_sdk/integrations/anthropic.py:805-813`
The _wrap_close function calls _finish_streaming_span() without wrapping it in capture_internal_exceptions(), unlike the same call in _wrap_synchronous_message_iterator() (line 455). If an exception occurs during span finishing (e.g., unexpected state, SDK bug), it would prevent the original close() method from being called, potentially leaking HTTP connections and propagating unexpected exceptions to user code.
Missing exception handling in _wrap_close may prevent HTTP connection from closing - `sentry_sdk/integrations/anthropic.py:108`
The _wrap_close function doesn't wrap its Sentry tracing logic with capture_internal_exceptions. If _finish_streaming_span or any internal Sentry operation throws an exception, the original close() method (f(self)) will never be called. This could leave the underlying HTTP connection open, causing resource leaks. The analogous _wrap_synchronous_message_iterator already correctly uses capture_internal_exceptions in its finally block.
4 skills analyzed
| Skill | Findings | Duration | Cost |
|---|---|---|---|
| code-review | 2 | 3m 4s | $1.66 |
| find-bugs | 1 | 6m 43s | $3.12 |
| skill-scanner | 0 | 3m 14s | $0.59 |
| security-review | 0 | 2m 20s | $0.83 |
Duration: 15m 21s · Tokens: 3.9M in / 41.0k out · Cost: $6.23 (+extraction: $0.00, +merge: $0.00, +fix_gate: $0.00, +dedup: $0.02)