Skip to content

.

4b2147d
Select commit
Loading
Failed to load commit list.
Draft

[do not merge] feat: Span streaming & new span API #5551

.
4b2147d
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden: find-bugs completed Mar 16, 2026 in 15m 32s

5 issues

find-bugs: Found 5 issues (1 high, 4 medium)

High

Method assignment is inverted: Span doesn't have set_attribute, StreamedSpan doesn't have set_data - `sentry_sdk/integrations/openai_agents/utils.py:55-58`

The code incorrectly assigns span.set_attribute for Span instances and span.set_data for StreamedSpan instances. However, Span (in tracing.py) only has set_data() method (line 590), while StreamedSpan (in traces.py) only has set_attribute() method (line 406). This will cause an AttributeError at runtime when _record_exception_on_span is called, failing to record exception data on spans.

Also found at:

  • sentry_sdk/integrations/sqlalchemy.py:3
  • sentry_sdk/integrations/sqlalchemy.py:102

Medium

StreamedSpan instances not closed when Anthropic API call fails - `sentry_sdk/integrations/anthropic.py:734-736`

The code change to isinstance(span, Span) excludes StreamedSpan instances from the error cleanup path. When span streaming is enabled and an Anthropic API call fails, set_span_errored() sets span.status = SpanStatus.ERROR ("error"), but the finally block only checks for SPANSTATUS.INTERNAL_ERROR ("internal_error") on legacy Span types. This causes StreamedSpan instances to remain unclosed when errors occur, potentially causing resource leaks and incorrect span timing in traces.

Also found at:

  • sentry_sdk/integrations/redis/_async_common.py:145-147
HTTP method filtering bypassed in span streaming mode - `sentry_sdk/integrations/asgi.py:238-241`

In the span streaming branch, spans are always created regardless of whether the HTTP method is in http_methods_to_capture. The legacy branch correctly skips transaction creation when ty == "http" and method not in self.http_methods_to_capture (resulting in transaction = None and nullcontext()). However, in span streaming mode, sentry_sdk.traces.start_span() is called unconditionally on line 238-240, creating spans for all HTTP requests including those that should be filtered out.

UnboundLocalError in finally block when Redis command raises exception - `sentry_sdk/integrations/redis/_sync_common.py:151-160`

When old_execute_command raises an exception, the finally block attempts to call _set_cache_data(cache_span, self, cache_properties, value) on line 158, but value is never assigned when an exception occurs. This results in an UnboundLocalError. While capture_internal_exceptions() suppresses this error, it masks the underlying bug and prevents proper cache span data from being recorded. The fix should initialize value = None before the try block.

Also found at:

  • sentry_sdk/integrations/redis/_async_common.py:147
HTTP status code attribute missing in streaming span mode - `sentry_sdk/integrations/stdlib.py:175-177`

When using span streaming mode, the getresponse handler sets the span status and reason but omits the HTTP status code attribute (SPANDATA.HTTP_STATUS_CODE). The legacy code path calls span.set_http_status(int(rv.status)) which sets both the span status and stores the actual status code value. In streaming mode, the status code value is lost, which degrades telemetry data quality for HTTP client spans.

Also found at:

  • sentry_sdk/integrations/httpx.py:116-118
  • sentry_sdk/integrations/httpx.py:199-201

Duration: 15m 19s · Tokens: 14.1M in / 132.3k out · Cost: $20.95 (+extraction: $0.02, +merge: $0.00, +fix_gate: $0.01)

Annotations

Check failure on line 58 in sentry_sdk/integrations/openai_agents/utils.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

Method assignment is inverted: Span doesn't have set_attribute, StreamedSpan doesn't have set_data

The code incorrectly assigns `span.set_attribute` for `Span` instances and `span.set_data` for `StreamedSpan` instances. However, `Span` (in `tracing.py`) only has `set_data()` method (line 590), while `StreamedSpan` (in `traces.py`) only has `set_attribute()` method (line 406). This will cause an `AttributeError` at runtime when `_record_exception_on_span` is called, failing to record exception data on spans.

Check failure on line 3 in sentry_sdk/integrations/sqlalchemy.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

[EX9-3GL] Method assignment is inverted: Span doesn't have set_attribute, StreamedSpan doesn't have set_data (additional location)

The code incorrectly assigns `span.set_attribute` for `Span` instances and `span.set_data` for `StreamedSpan` instances. However, `Span` (in `tracing.py`) only has `set_data()` method (line 590), while `StreamedSpan` (in `traces.py`) only has `set_attribute()` method (line 406). This will cause an `AttributeError` at runtime when `_record_exception_on_span` is called, failing to record exception data on spans.

Check failure on line 102 in sentry_sdk/integrations/sqlalchemy.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

[EX9-3GL] Method assignment is inverted: Span doesn't have set_attribute, StreamedSpan doesn't have set_data (additional location)

The code incorrectly assigns `span.set_attribute` for `Span` instances and `span.set_data` for `StreamedSpan` instances. However, `Span` (in `tracing.py`) only has `set_data()` method (line 590), while `StreamedSpan` (in `traces.py`) only has `set_attribute()` method (line 406). This will cause an `AttributeError` at runtime when `_record_exception_on_span` is called, failing to record exception data on spans.

Check warning on line 736 in sentry_sdk/integrations/anthropic.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

StreamedSpan instances not closed when Anthropic API call fails

The code change to `isinstance(span, Span)` excludes `StreamedSpan` instances from the error cleanup path. When span streaming is enabled and an Anthropic API call fails, `set_span_errored()` sets `span.status = SpanStatus.ERROR` ("error"), but the finally block only checks for `SPANSTATUS.INTERNAL_ERROR` ("internal_error") on legacy `Span` types. This causes `StreamedSpan` instances to remain unclosed when errors occur, potentially causing resource leaks and incorrect span timing in traces.

Check warning on line 147 in sentry_sdk/integrations/redis/_async_common.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

[8NA-MBF] StreamedSpan instances not closed when Anthropic API call fails (additional location)

The code change to `isinstance(span, Span)` excludes `StreamedSpan` instances from the error cleanup path. When span streaming is enabled and an Anthropic API call fails, `set_span_errored()` sets `span.status = SpanStatus.ERROR` ("error"), but the finally block only checks for `SPANSTATUS.INTERNAL_ERROR` ("internal_error") on legacy `Span` types. This causes `StreamedSpan` instances to remain unclosed when errors occur, potentially causing resource leaks and incorrect span timing in traces.

Check warning on line 241 in sentry_sdk/integrations/asgi.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

HTTP method filtering bypassed in span streaming mode

In the span streaming branch, spans are always created regardless of whether the HTTP method is in `http_methods_to_capture`. The legacy branch correctly skips transaction creation when `ty == "http"` and `method not in self.http_methods_to_capture` (resulting in `transaction = None` and `nullcontext()`). However, in span streaming mode, `sentry_sdk.traces.start_span()` is called unconditionally on line 238-240, creating spans for all HTTP requests including those that should be filtered out.

Check warning on line 160 in sentry_sdk/integrations/redis/_sync_common.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

UnboundLocalError in finally block when Redis command raises exception

When `old_execute_command` raises an exception, the `finally` block attempts to call `_set_cache_data(cache_span, self, cache_properties, value)` on line 158, but `value` is never assigned when an exception occurs. This results in an `UnboundLocalError`. While `capture_internal_exceptions()` suppresses this error, it masks the underlying bug and prevents proper cache span data from being recorded. The fix should initialize `value = None` before the try block.

Check warning on line 147 in sentry_sdk/integrations/redis/_async_common.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

[T47-M85] UnboundLocalError in finally block when Redis command raises exception (additional location)

When `old_execute_command` raises an exception, the `finally` block attempts to call `_set_cache_data(cache_span, self, cache_properties, value)` on line 158, but `value` is never assigned when an exception occurs. This results in an `UnboundLocalError`. While `capture_internal_exceptions()` suppresses this error, it masks the underlying bug and prevents proper cache span data from being recorded. The fix should initialize `value = None` before the try block.

Check warning on line 177 in sentry_sdk/integrations/stdlib.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

HTTP status code attribute missing in streaming span mode

When using span streaming mode, the getresponse handler sets the span status and reason but omits the HTTP status code attribute (SPANDATA.HTTP_STATUS_CODE). The legacy code path calls `span.set_http_status(int(rv.status))` which sets both the span status and stores the actual status code value. In streaming mode, the status code value is lost, which degrades telemetry data quality for HTTP client spans.

Check warning on line 118 in sentry_sdk/integrations/httpx.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

[V5M-8MZ] HTTP status code attribute missing in streaming span mode (additional location)

When using span streaming mode, the getresponse handler sets the span status and reason but omits the HTTP status code attribute (SPANDATA.HTTP_STATUS_CODE). The legacy code path calls `span.set_http_status(int(rv.status))` which sets both the span status and stores the actual status code value. In streaming mode, the status code value is lost, which degrades telemetry data quality for HTTP client spans.

Check warning on line 201 in sentry_sdk/integrations/httpx.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: find-bugs

[V5M-8MZ] HTTP status code attribute missing in streaming span mode (additional location)

When using span streaming mode, the getresponse handler sets the span status and reason but omits the HTTP status code attribute (SPANDATA.HTTP_STATUS_CODE). The legacy code path calls `span.set_http_status(int(rv.status))` which sets both the span status and stores the actual status code value. In streaming mode, the status code value is lost, which degrades telemetry data quality for HTTP client spans.