Skip to content

cleanup

cc51564
Select commit
Loading
Failed to load commit list.
Draft

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

cleanup
cc51564
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden: code-review completed Mar 11, 2026 in 54m 28s

5 issues

code-review: Found 5 issues (2 high, 3 medium)

High

StreamedSpan.set_status() method does not exist - will cause AttributeError - `sentry_sdk/integrations/sqlalchemy.py:102`

The code calls span.set_status(SpanStatus.ERROR) on a StreamedSpan instance, but StreamedSpan only has a status property setter, not a set_status() method. This will raise an AttributeError at runtime when a SQL error occurs in streaming mode. The legacy Span class in tracing.py has set_status() method, but StreamedSpan in traces.py does not.

Also found at:

  • sentry_sdk/integrations/celery/__init__.py:104-105
NoOpStreamedSpan will crash when _get_trace_context() is called due to None _segment - `sentry_sdk/traces.py:586`

The NoOpStreamedSpan.__init__ sets self._segment = None (line 586), but the class inherits _get_trace_context() and _dynamic_sampling_context() from StreamedSpan without overriding them. When _get_trace_context() is called (e.g., from scope.get_trace_context() when a NoOpStreamedSpan is the active span), it will invoke _dynamic_sampling_context() which accesses self._segment._get_baggage(). This causes an AttributeError: 'NoneType' object has no attribute '_get_baggage' since _segment is None.

Medium

Streaming mode creates spans for HTTP methods that should be skipped - `sentry_sdk/integrations/asgi.py:238-241`

When ty == "http" but method not in self.http_methods_to_capture, the legacy path correctly skips span creation by keeping transaction = None. However, the streaming path unconditionally calls start_span() at line 238, creating spans for HTTP methods that should be excluded per http_methods_to_capture. Additionally, neither continue_trace() nor new_trace() is called in this case, which may cause trace context issues.

Also found at:

  • sentry_sdk/integrations/httpx.py:113-118
  • sentry_sdk/integrations/stdlib.py:175-177
Missing exception handling causes spans to leak if Redis command fails - `sentry_sdk/integrations/redis/_async_common.py:145`

The _sentry_execute_command async function manually calls __enter__() on spans but lacks a try...finally block around await old_execute_command(). If the Redis command raises an exception, db_span.__exit__() and cache_span.__exit__() are never called, leaving spans unclosed. This contrasts with the sync version in _sync_common.py which properly uses try...finally. Leaked spans may cause incorrect trace hierarchies and resource leaks.

Also found at:

  • sentry_sdk/integrations/redis/_sync_common.py:158
New public API method lacks test coverage - `sentry_sdk/scope.py:1348-1349`

The new set_propagation_context method is a public API added to the Scope class but has no corresponding tests. While it delegates to generate_propagation_context, tests should verify the method behaves correctly and is accessible from expected entry points.


Duration: 54m 19s · Tokens: 16.7M in / 186.9k out · Cost: $21.95 (+extraction: $0.02, +merge: $0.00, +fix_gate: $0.01)

Annotations

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

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

StreamedSpan.set_status() method does not exist - will cause AttributeError

The code calls `span.set_status(SpanStatus.ERROR)` on a `StreamedSpan` instance, but `StreamedSpan` only has a `status` property setter, not a `set_status()` method. This will raise an `AttributeError` at runtime when a SQL error occurs in streaming mode. The legacy `Span` class in `tracing.py` has `set_status()` method, but `StreamedSpan` in `traces.py` does not.

Check failure on line 105 in sentry_sdk/integrations/celery/__init__.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

[RK7-GV6] StreamedSpan.set_status() method does not exist - will cause AttributeError (additional location)

The code calls `span.set_status(SpanStatus.ERROR)` on a `StreamedSpan` instance, but `StreamedSpan` only has a `status` property setter, not a `set_status()` method. This will raise an `AttributeError` at runtime when a SQL error occurs in streaming mode. The legacy `Span` class in `tracing.py` has `set_status()` method, but `StreamedSpan` in `traces.py` does not.

Check failure on line 586 in sentry_sdk/traces.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

NoOpStreamedSpan will crash when _get_trace_context() is called due to None _segment

The `NoOpStreamedSpan.__init__` sets `self._segment = None` (line 586), but the class inherits `_get_trace_context()` and `_dynamic_sampling_context()` from `StreamedSpan` without overriding them. When `_get_trace_context()` is called (e.g., from `scope.get_trace_context()` when a NoOpStreamedSpan is the active span), it will invoke `_dynamic_sampling_context()` which accesses `self._segment._get_baggage()`. This causes an `AttributeError: 'NoneType' object has no attribute '_get_baggage'` since `_segment` is `None`.

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

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

Streaming mode creates spans for HTTP methods that should be skipped

When `ty == "http"` but `method not in self.http_methods_to_capture`, the legacy path correctly skips span creation by keeping `transaction = None`. However, the streaming path unconditionally calls `start_span()` at line 238, creating spans for HTTP methods that should be excluded per `http_methods_to_capture`. Additionally, neither `continue_trace()` nor `new_trace()` is called in this case, which may cause trace context issues.

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

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

[RZE-URN] Streaming mode creates spans for HTTP methods that should be skipped (additional location)

When `ty == "http"` but `method not in self.http_methods_to_capture`, the legacy path correctly skips span creation by keeping `transaction = None`. However, the streaming path unconditionally calls `start_span()` at line 238, creating spans for HTTP methods that should be excluded per `http_methods_to_capture`. Additionally, neither `continue_trace()` nor `new_trace()` is called in this case, which may cause trace context issues.

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

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

[RZE-URN] Streaming mode creates spans for HTTP methods that should be skipped (additional location)

When `ty == "http"` but `method not in self.http_methods_to_capture`, the legacy path correctly skips span creation by keeping `transaction = None`. However, the streaming path unconditionally calls `start_span()` at line 238, creating spans for HTTP methods that should be excluded per `http_methods_to_capture`. Additionally, neither `continue_trace()` nor `new_trace()` is called in this case, which may cause trace context issues.

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

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

Missing exception handling causes spans to leak if Redis command fails

The `_sentry_execute_command` async function manually calls `__enter__()` on spans but lacks a `try...finally` block around `await old_execute_command()`. If the Redis command raises an exception, `db_span.__exit__()` and `cache_span.__exit__()` are never called, leaving spans unclosed. This contrasts with the sync version in `_sync_common.py` which properly uses `try...finally`. Leaked spans may cause incorrect trace hierarchies and resource leaks.

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

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

[7DC-684] Missing exception handling causes spans to leak if Redis command fails (additional location)

The `_sentry_execute_command` async function manually calls `__enter__()` on spans but lacks a `try...finally` block around `await old_execute_command()`. If the Redis command raises an exception, `db_span.__exit__()` and `cache_span.__exit__()` are never called, leaving spans unclosed. This contrasts with the sync version in `_sync_common.py` which properly uses `try...finally`. Leaked spans may cause incorrect trace hierarchies and resource leaks.

Check warning on line 1349 in sentry_sdk/scope.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

New public API method lacks test coverage

The new `set_propagation_context` method is a public API added to the Scope class but has no corresponding tests. While it delegates to `generate_propagation_context`, tests should verify the method behaves correctly and is accessible from expected entry points.