ref: Support outgoing trace propagation in span first (18) #5638
5 issues
High
NoOpStreamedSpan._iter_headers() raises AttributeError due to uninitialized _segment - `sentry_sdk/traces.py:504-512`
The new _iter_headers() method accesses self._segment but NoOpStreamedSpan does not initialize this attribute (it doesn't call super().__init__() and only sets _scope, _unsampled_reason, and _finished). In scope.py:688, span._iter_headers() is called without a guard against NoOpStreamedSpan, unlike _to_baggage() (line 607) and _get_trace_context() (line 621) which have not isinstance(self.span, NoOpStreamedSpan) checks. When iter_trace_propagation_headers() is called while a NoOpStreamedSpan is active, this will raise AttributeError: 'NoOpStreamedSpan' object has no attribute '_segment'.
NoOpStreamedSpan missing _segment attribute causes AttributeError in inherited methods - `sentry_sdk/traces.py:504-512`
The new _iter_headers(), _to_baggage(), and _dynamic_sampling_context() methods access self._segment, but NoOpStreamedSpan.__init__() does not initialize this attribute. When these inherited methods are called on a NoOpStreamedSpan instance (e.g., through scope.iter_trace_propagation_headers() which doesn't guard against NoOpStreamedSpan), an AttributeError will be raised, crashing HTTP client integrations (stdlib, httpx, aiohttp, grpc, celery, etc.).
Also found at:
sentry_sdk/traces.py:492-502sentry_sdk/traces.py:514-529sentry_sdk/tracing_utils.py:1123-1124
Medium
Inconsistent handling of NoOpStreamedSpan between transaction setter and set_transaction_name - `sentry_sdk/scope.py:827-836`
The set_transaction_name method (lines 841-856) explicitly checks for NoOpStreamedSpan first and silently returns, then separately handles StreamedSpan. However, the transaction setter (lines 826-836) only checks for StreamedSpan without explicitly handling NoOpStreamedSpan first. Since NoOpStreamedSpan is a subclass of StreamedSpan, this causes NoOpStreamedSpan to trigger a deprecation warning in the setter, which is inconsistent with the silent handling in set_transaction_name. Users with NoOpStreamedSpan (unsampled traces) will see unexpected deprecation warnings.
Also found at:
sentry_sdk/scope.py:833
Low
Inconsistent use of self._span vs self.span in get_trace_context - `sentry_sdk/scope.py:620-621`
In get_trace_context, line 620 checks self._span is not None but line 621 checks isinstance(self.span, NoOpStreamedSpan), mixing the private attribute with the public property. This is inconsistent with get_traceparent and get_baggage which consistently use self.span throughout. While currently functionally equivalent (since self.span just returns self._span), this inconsistency could cause subtle issues if the property behavior changes in the future.
Redundant Pattern import immediately overwritten - `sentry_sdk/tracing_utils.py:11`
Line 11 imports Pattern from typing, but this import is immediately overwritten by the try/except block at lines 15-19 which imports Pattern from re (Python 3.7+) or typing (Python 3.6 fallback). The import at line 11 serves no purpose since Python's module-level imports are executed sequentially and the later import overwrites it.
4 skills analyzed
| Skill | Findings | Duration | Cost |
|---|---|---|---|
| code-review | 2 | 9m 35s | $4.59 |
| find-bugs | 3 | 13m 44s | $10.25 |
| skill-scanner | 0 | 2m 34s | $1.58 |
| security-review | 0 | 13m 28s | $1.51 |
Duration: 39m 22s · Tokens: 13.0M in / 121.2k out · Cost: $17.95 (+extraction: $0.01, +merge: $0.00, +fix_gate: $0.01, +dedup: $0.01)