[do not merge] feat: Span streaming & new span API #5551
3 issues
find-bugs: Found 3 issues (1 high, 2 medium)
High
StreamedSpan.set_status() method does not exist - will raise AttributeError - `sentry_sdk/integrations/sqlalchemy.py:102`
The code at line 102 calls span.set_status(SpanStatus.ERROR) on a StreamedSpan object, but StreamedSpan class does not have a set_status() method. Unlike the legacy Span class which has set_status(), StreamedSpan only provides a status property setter. This will cause an AttributeError at runtime when span streaming mode is enabled and a SQL error occurs.
Also found at:
sentry_sdk/integrations/strawberry.py:226
Medium
StreamedSpan missing HTTP status code attribute in sync httpx client - `sentry_sdk/integrations/httpx.py:116-118`
When using span streaming mode, the HTTP response status code is not captured as an attribute. Lines 116-118 set span.status to 'ok' or 'error' and add a 'reason' attribute, but unlike the legacy set_http_status() path (line 120) or the ASGI integration (which sets http.response.status_code), the actual numeric status code is never recorded. This causes data loss - users cannot see the specific HTTP status code (e.g., 404 vs 500) in their telemetry.
Also found at:
sentry_sdk/integrations/httpx.py:199-201sentry_sdk/integrations/stdlib.py:175-177
Async Redis spans leak when command raises exception - `sentry_sdk/integrations/redis/_async_common.py:145-156`
In _sentry_execute_command, the db_span and cache_span are manually entered with __enter__() but are not protected by a try/finally block. If old_execute_command(self, name, *args, **kwargs) raises an exception, __exit__() is never called on either span. This causes span leaks and leaves the scope in an inconsistent state (the span remains as the active span on the scope). The sync version in _sync_common.py correctly uses try/finally for this (lines 151-160).
Also found at:
sentry_sdk/integrations/redis/_sync_common.py:158
Duration: 24m 1s · Tokens: 14.5M in / 136.7k out · Cost: $20.30 (+extraction: $0.03, +merge: $0.00, +fix_gate: $0.01)
Annotations
Check failure on line 102 in sentry_sdk/integrations/sqlalchemy.py
sentry-warden / warden: find-bugs
StreamedSpan.set_status() method does not exist - will raise AttributeError
The code at line 102 calls `span.set_status(SpanStatus.ERROR)` on a `StreamedSpan` object, but `StreamedSpan` class does not have a `set_status()` method. Unlike the legacy `Span` class which has `set_status()`, `StreamedSpan` only provides a `status` property setter. This will cause an `AttributeError` at runtime when span streaming mode is enabled and a SQL error occurs.
Check failure on line 226 in sentry_sdk/integrations/strawberry.py
sentry-warden / warden: find-bugs
[ZHH-LJW] StreamedSpan.set_status() method does not exist - will raise AttributeError (additional location)
The code at line 102 calls `span.set_status(SpanStatus.ERROR)` on a `StreamedSpan` object, but `StreamedSpan` class does not have a `set_status()` method. Unlike the legacy `Span` class which has `set_status()`, `StreamedSpan` only provides a `status` property setter. This will cause an `AttributeError` at runtime when span streaming mode is enabled and a SQL error occurs.
Check warning on line 118 in sentry_sdk/integrations/httpx.py
sentry-warden / warden: find-bugs
StreamedSpan missing HTTP status code attribute in sync httpx client
When using span streaming mode, the HTTP response status code is not captured as an attribute. Lines 116-118 set `span.status` to 'ok' or 'error' and add a 'reason' attribute, but unlike the legacy `set_http_status()` path (line 120) or the ASGI integration (which sets `http.response.status_code`), the actual numeric status code is never recorded. This causes data loss - users cannot see the specific HTTP status code (e.g., 404 vs 500) in their telemetry.
Check warning on line 201 in sentry_sdk/integrations/httpx.py
sentry-warden / warden: find-bugs
[6BY-TG9] StreamedSpan missing HTTP status code attribute in sync httpx client (additional location)
When using span streaming mode, the HTTP response status code is not captured as an attribute. Lines 116-118 set `span.status` to 'ok' or 'error' and add a 'reason' attribute, but unlike the legacy `set_http_status()` path (line 120) or the ASGI integration (which sets `http.response.status_code`), the actual numeric status code is never recorded. This causes data loss - users cannot see the specific HTTP status code (e.g., 404 vs 500) in their telemetry.
Check warning on line 177 in sentry_sdk/integrations/stdlib.py
sentry-warden / warden: find-bugs
[6BY-TG9] StreamedSpan missing HTTP status code attribute in sync httpx client (additional location)
When using span streaming mode, the HTTP response status code is not captured as an attribute. Lines 116-118 set `span.status` to 'ok' or 'error' and add a 'reason' attribute, but unlike the legacy `set_http_status()` path (line 120) or the ASGI integration (which sets `http.response.status_code`), the actual numeric status code is never recorded. This causes data loss - users cannot see the specific HTTP status code (e.g., 404 vs 500) in their telemetry.
Check warning on line 156 in sentry_sdk/integrations/redis/_async_common.py
sentry-warden / warden: find-bugs
Async Redis spans leak when command raises exception
In `_sentry_execute_command`, the `db_span` and `cache_span` are manually entered with `__enter__()` but are not protected by a `try/finally` block. If `old_execute_command(self, name, *args, **kwargs)` raises an exception, `__exit__()` is never called on either span. This causes span leaks and leaves the scope in an inconsistent state (the span remains as the active span on the scope). The sync version in `_sync_common.py` correctly uses `try/finally` for this (lines 151-160).
Check warning on line 158 in sentry_sdk/integrations/redis/_sync_common.py
sentry-warden / warden: find-bugs
[UMK-U5P] Async Redis spans leak when command raises exception (additional location)
In `_sentry_execute_command`, the `db_span` and `cache_span` are manually entered with `__enter__()` but are not protected by a `try/finally` block. If `old_execute_command(self, name, *args, **kwargs)` raises an exception, `__exit__()` is never called on either span. This causes span leaks and leaves the scope in an inconsistent state (the span remains as the active span on the scope). The sync version in `_sync_common.py` correctly uses `try/finally` for this (lines 151-160).