[do not merge] feat: Span streaming & new span API #1104
Triggered via pull request
February 26, 2026 14:23
sentrivana
synchronize
#5551
Status
Success
Total duration
22s
Artifacts
–
changelog-preview.yml
on: pull_request_target
changelog-preview
/
preview
17s
Annotations
7 errors and 4 warnings
|
API incompatibility: get_start_span_function returns function with incompatible signature in streaming mode:
sentry_sdk/ai/utils.py#L539
When streaming mode is enabled or the current span is a StreamedSpan, `get_start_span_function()` returns `sentry_sdk.traces.start_span` which accepts `(name, attributes, parent_span)`. However, all callers (e.g., anthropic.py:408, google_genai, langchain, litellm, mcp, openai_agents) invoke it with `(op=..., name=..., origin=...)`. This will cause a `TypeError` at runtime because `op` and `origin` are not accepted parameters, and `name` is a positional-only argument in the new API.
|
|
[6TJ-X3B] API incompatibility: get_start_span_function returns function with incompatible signature in streaming mode (additional location):
sentry_sdk/integrations/celery/__init__.py#L330
When streaming mode is enabled or the current span is a StreamedSpan, `get_start_span_function()` returns `sentry_sdk.traces.start_span` which accepts `(name, attributes, parent_span)`. However, all callers (e.g., anthropic.py:408, google_genai, langchain, litellm, mcp, openai_agents) invoke it with `(op=..., name=..., origin=...)`. This will cause a `TypeError` at runtime because `op` and `origin` are not accepted parameters, and `name` is a positional-only argument in the new API.
|
|
Spans leak when Redis command throws an exception:
sentry_sdk/integrations/redis/_async_common.py#L135
In `_sentry_execute_command`, the `db_span` and `cache_span` are opened via `__enter__()` (lines 120, 135) but their `__exit__()` calls (lines 142, 146) are not protected by try/finally. If `await old_execute_command()` raises an exception, the spans will never be closed, causing resource leaks and incorrect span hierarchy. The sync version in `_sync_common.py` correctly uses `try...finally` to ensure spans are always closed.
|
|
[CAD-53H] Spans leak when Redis command throws an exception (additional location):
sentry_sdk/integrations/redis/_sync_common.py#L141
In `_sentry_execute_command`, the `db_span` and `cache_span` are opened via `__enter__()` (lines 120, 135) but their `__exit__()` calls (lines 142, 146) are not protected by try/finally. If `await old_execute_command()` raises an exception, the spans will never be closed, causing resource leaks and incorrect span hierarchy. The sync version in `_sync_common.py` correctly uses `try...finally` to ensure spans are always closed.
|
|
StreamedSpan created in on_operation() is never started, causing silent failures when end() is called:
sentry_sdk/integrations/strawberry.py#L192
In the span streaming branch, `self.graphql_span` is created via `sentry_sdk.traces.start_span()` at line 192 but is never started with `span.start()` or used as a context manager. When `self.graphql_span.end()` is called at line 237, it calls `__exit__()` which tries to access `self._context_manager_state` that was only set in `__enter__()`. Since the span was never entered, this raises an AttributeError that gets silently caught by `capture_internal_exceptions()`. The span will never be properly sent to Sentry.
|
|
[PFS-B2J] StreamedSpan created in on_operation() is never started, causing silent failures when end() is called (additional location):
sentry_sdk/integrations/strawberry.py#L244
In the span streaming branch, `self.graphql_span` is created via `sentry_sdk.traces.start_span()` at line 192 but is never started with `span.start()` or used as a context manager. When `self.graphql_span.end()` is called at line 237, it calls `__exit__()` which tries to access `self._context_manager_state` that was only set in `__enter__()`. Since the span was never entered, this raises an AttributeError that gets silently caught by `capture_internal_exceptions()`. The span will never be properly sent to Sentry.
|
|
[PFS-B2J] StreamedSpan created in on_operation() is never started, causing silent failures when end() is called (additional location):
sentry_sdk/integrations/strawberry.py#L270
In the span streaming branch, `self.graphql_span` is created via `sentry_sdk.traces.start_span()` at line 192 but is never started with `span.start()` or used as a context manager. When `self.graphql_span.end()` is called at line 237, it calls `__exit__()` which tries to access `self._context_manager_state` that was only set in `__enter__()`. Since the span was never entered, this raises an AttributeError that gets silently caught by `capture_internal_exceptions()`. The span will never be properly sent to Sentry.
|
|
Missing test coverage for new StreamedSpan code paths:
sentry_sdk/integrations/rust_tracing.py#L215
The changes add new code branches for handling `StreamedSpan` in streaming mode (lines 215-221, 231-237, 245-255, 265-266, 276-285), but the existing tests only exercise the legacy `Span` code path via `start_transaction`. The new streaming mode paths (`_experiments={"trace_lifecycle": "stream"}`) have no test coverage in the rust_tracing integration tests.
|
|
NoOpStreamedSpan methods can raise AttributeError when accessing segment:
sentry_sdk/traces.py#L666
`NoOpStreamedSpan.__init__` sets `self.segment = None`, but it does not override inherited methods like `dynamic_sampling_context()`, `to_baggage()`, `iter_headers()`, and `get_baggage()` which all access `self.segment.get_baggage()`. Calling any of these methods on a `NoOpStreamedSpan` instance will raise `AttributeError: 'NoneType' object has no attribute 'get_baggage'`.
|
|
[WWD-AJB] NoOpStreamedSpan methods can raise AttributeError when accessing segment (additional location):
sentry_sdk/traces.py#L676
`NoOpStreamedSpan.__init__` sets `self.segment = None`, but it does not override inherited methods like `dynamic_sampling_context()`, `to_baggage()`, `iter_headers()`, and `get_baggage()` which all access `self.segment.get_baggage()`. Calling any of these methods on a `NoOpStreamedSpan` instance will raise `AttributeError: 'NoneType' object has no attribute 'get_baggage'`.
|
|
Lowercase dict[] type hint breaks Python 3.6-3.8 compatibility:
sentry_sdk/tracing_utils.py#L478
The type annotation `Optional[dict[str, Any]]` uses lowercase `dict` with subscript syntax, which is only supported natively in Python 3.9+. While string annotations defer evaluation during normal import, calling `typing.get_type_hints()` on `PropagationContext` would raise `TypeError` on Python 3.6-3.8 since `dict` doesn't support subscripting. The SDK supports Python 3.6+ per setup.py. Should use `Dict` from typing module for compatibility.
|