From 5dae95a4552d9e723bd87b6e14bb0411a553edca Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Tue, 2 Dec 2025 14:34:33 +0100 Subject: [PATCH] Make PropagationContext.from_incoming_data always return a PropagationContext When there is any sort of incoming data, and since `continue_trace` is always intended to be at a system boundary, we always want to force a new trace if there's no incoming propagation or an incorrect propagation header. What previously happened is in these cases, a single `trace_id` was kept alive in the `propagation_context` even when these were just meant to be new independent traces (see screenshot). I think this will actually solve many complaints about long living traces that were never supposed to be such. --- sentry_sdk/scope.py | 9 +++++---- sentry_sdk/tracing_utils.py | 8 ++++---- tests/tracing/test_integration_tests.py | 11 +++++++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 2038dc4501..466e1b5b12 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -510,11 +510,12 @@ def generate_propagation_context(self, incoming_data=None): If there is `incoming_data` overwrite existing propagation context. If there is no `incoming_data` create new propagation context, but do NOT overwrite if already existing. """ - if incoming_data: - propagation_context = PropagationContext.from_incoming_data(incoming_data) - if propagation_context is not None: - self._propagation_context = propagation_context + if incoming_data is not None: + self._propagation_context = PropagationContext.from_incoming_data( + incoming_data + ) + # TODO-neel this below is a BIG code smell but requires a bunch of other refactoring if self._type != ScopeType.CURRENT: if self._propagation_context is None: self.set_new_propagation_context() diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index b6c184838c..69ba197ddf 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -447,7 +447,8 @@ def __init__( @classmethod def from_incoming_data(cls, incoming_data): - # type: (Dict[str, Any]) -> Optional[PropagationContext] + # type: (Dict[str, Any]) -> PropagationContext + propagation_context = PropagationContext() normalized_data = normalize_incoming_data(incoming_data) sentry_trace_header = normalized_data.get(SENTRY_TRACE_HEADER_NAME) @@ -455,7 +456,7 @@ def from_incoming_data(cls, incoming_data): # nothing to propagate if no sentry-trace if sentrytrace_data is None: - return None + return propagation_context baggage_header = normalized_data.get(BAGGAGE_HEADER_NAME) baggage = ( @@ -463,9 +464,8 @@ def from_incoming_data(cls, incoming_data): ) if not _should_continue_trace(baggage): - return None + return propagation_context - propagation_context = PropagationContext() propagation_context.update(sentrytrace_data) if baggage: propagation_context.baggage = baggage diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index 117f2ef844..80945c1db5 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -419,3 +419,14 @@ def test_continue_trace_strict_trace_continuation( ) assert transaction.parent_span_id != "1234567890abcdef" assert not transaction.parent_sampled + + +def test_continue_trace_forces_new_traces_when_no_propagation(sentry_init): + """This is to make sure we don't have a long running trace because of TWP logic for the no propagation case.""" + + sentry_init(traces_sample_rate=1.0) + + tx1 = continue_trace({}, name="tx1") + tx2 = continue_trace({}, name="tx2") + + assert tx1.trace_id != tx2.trace_id