From 530a858fbb547ee4159c1a67e8d0b2ee9e80560b Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 10 Apr 2026 10:17:23 +0200 Subject: [PATCH 1/3] fix(opentelemetry): Handle None span context --- .../opentelemetry/span_processor.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/sentry_sdk/integrations/opentelemetry/span_processor.py b/sentry_sdk/integrations/opentelemetry/span_processor.py index 282edbe2ab..f260ab532e 100644 --- a/sentry_sdk/integrations/opentelemetry/span_processor.py +++ b/sentry_sdk/integrations/opentelemetry/span_processor.py @@ -124,7 +124,8 @@ def on_start( if client.options["instrumenter"] != INSTRUMENTER.OTEL: return - if not otel_span.get_span_context().is_valid: + span_context = otel_span.get_span_context() + if span_context is None or not span_context.is_valid: return if self._is_sentry_span(otel_span): @@ -183,7 +184,7 @@ def on_end(self, otel_span: "OTelSpan") -> None: return span_context = otel_span.get_span_context() - if not span_context.is_valid: + if span_context is None or not span_context.is_valid: return span_id = format_span_id(span_context.span_id) @@ -263,16 +264,17 @@ def _get_trace_data( trace_data: "dict[str, Any]" = {} span_context = otel_span.get_span_context() - span_id = format_span_id(span_context.span_id) - trace_data["span_id"] = span_id + if span_context is not None: + span_id = format_span_id(span_context.span_id) + trace_data["span_id"] = span_id - trace_id = format_trace_id(span_context.trace_id) - trace_data["trace_id"] = trace_id + trace_id = format_trace_id(span_context.trace_id) + trace_data["trace_id"] = trace_id - parent_span_id = ( - format_span_id(otel_span.parent.span_id) if otel_span.parent else None - ) - trace_data["parent_span_id"] = parent_span_id + parent_span_id = ( + format_span_id(otel_span.parent.span_id) if otel_span.parent else None + ) + trace_data["parent_span_id"] = parent_span_id sentry_trace_data = get_value(SENTRY_TRACE_KEY, parent_context) sentry_trace_data = cast("dict[str, Union[str, bool, None]]", sentry_trace_data) From 3bd94e5eba1cb3c1ee0eb90ca8def892a59de4e7 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 10 Apr 2026 10:24:50 +0200 Subject: [PATCH 2/3] simplify --- .../opentelemetry/span_processor.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sentry_sdk/integrations/opentelemetry/span_processor.py b/sentry_sdk/integrations/opentelemetry/span_processor.py index f260ab532e..88842dcaa3 100644 --- a/sentry_sdk/integrations/opentelemetry/span_processor.py +++ b/sentry_sdk/integrations/opentelemetry/span_processor.py @@ -34,6 +34,7 @@ if TYPE_CHECKING: from typing import Any, Optional, Union from opentelemetry import context as context_api + from opentelemetry.trace import SpanContext from sentry_sdk._types import Event, Hint OPEN_TELEMETRY_CONTEXT = "otel" @@ -131,7 +132,7 @@ def on_start( if self._is_sentry_span(otel_span): return - trace_data = self._get_trace_data(otel_span, parent_context) + trace_data = self._get_trace_data(otel_span, span_context, parent_context) parent_span_id = trace_data["parent_span_id"] sentry_parent_span = ( @@ -256,25 +257,26 @@ def _get_otel_context(self, otel_span: "OTelSpan") -> "dict[str, Any]": return ctx def _get_trace_data( - self, otel_span: "OTelSpan", parent_context: "Optional[context_api.Context]" + self, + otel_span: "OTelSpan", + span_context: "SpanContext", + parent_context: "Optional[context_api.Context]", ) -> "dict[str, Any]": """ Extracts tracing information from one OTel span and its parent OTel context. """ trace_data: "dict[str, Any]" = {} - span_context = otel_span.get_span_context() - if span_context is not None: - span_id = format_span_id(span_context.span_id) - trace_data["span_id"] = span_id + span_id = format_span_id(span_context.span_id) + trace_data["span_id"] = span_id - trace_id = format_trace_id(span_context.trace_id) - trace_data["trace_id"] = trace_id + trace_id = format_trace_id(span_context.trace_id) + trace_data["trace_id"] = trace_id - parent_span_id = ( - format_span_id(otel_span.parent.span_id) if otel_span.parent else None - ) - trace_data["parent_span_id"] = parent_span_id + parent_span_id = ( + format_span_id(otel_span.parent.span_id) if otel_span.parent else None + ) + trace_data["parent_span_id"] = parent_span_id sentry_trace_data = get_value(SENTRY_TRACE_KEY, parent_context) sentry_trace_data = cast("dict[str, Union[str, bool, None]]", sentry_trace_data) From c3fdff988f037bd86941133e8846a92c4fb922d4 Mon Sep 17 00:00:00 2001 From: Alexander Alderman Webb Date: Fri, 10 Apr 2026 10:34:27 +0200 Subject: [PATCH 3/3] . --- .../opentelemetry/span_processor.py | 10 ++++++---- .../opentelemetry/test_span_processor.py | 20 ++++++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/sentry_sdk/integrations/opentelemetry/span_processor.py b/sentry_sdk/integrations/opentelemetry/span_processor.py index 88842dcaa3..8a589af308 100644 --- a/sentry_sdk/integrations/opentelemetry/span_processor.py +++ b/sentry_sdk/integrations/opentelemetry/span_processor.py @@ -132,7 +132,9 @@ def on_start( if self._is_sentry_span(otel_span): return - trace_data = self._get_trace_data(otel_span, span_context, parent_context) + trace_data = self._get_trace_data( + span_context, otel_span.parent, parent_context + ) parent_span_id = trace_data["parent_span_id"] sentry_parent_span = ( @@ -258,12 +260,12 @@ def _get_otel_context(self, otel_span: "OTelSpan") -> "dict[str, Any]": def _get_trace_data( self, - otel_span: "OTelSpan", span_context: "SpanContext", + parent_span_context: "Optional[SpanContext]", parent_context: "Optional[context_api.Context]", ) -> "dict[str, Any]": """ - Extracts tracing information from one OTel span and its parent OTel context. + Extracts tracing information from one OTel span's context and its parent OTel context. """ trace_data: "dict[str, Any]" = {} @@ -274,7 +276,7 @@ def _get_trace_data( trace_data["trace_id"] = trace_id parent_span_id = ( - format_span_id(otel_span.parent.span_id) if otel_span.parent else None + format_span_id(parent_span_context.span_id) if parent_span_context else None ) trace_data["parent_span_id"] = parent_span_id diff --git a/tests/integrations/opentelemetry/test_span_processor.py b/tests/integrations/opentelemetry/test_span_processor.py index af5cbdd3fb..e1cd849b94 100644 --- a/tests/integrations/opentelemetry/test_span_processor.py +++ b/tests/integrations/opentelemetry/test_span_processor.py @@ -68,7 +68,9 @@ def test_get_trace_data_with_span_and_trace(): parent_context = {} span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + sentry_trace_data = span_processor._get_trace_data( + otel_span.get_span_context(), otel_span.parent, parent_context + ) assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" assert sentry_trace_data["span_id"] == "1234567890abcdef" assert sentry_trace_data["parent_span_id"] is None @@ -90,7 +92,9 @@ def test_get_trace_data_with_span_and_trace_and_parent(): parent_context = {} span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + sentry_trace_data = span_processor._get_trace_data( + otel_span.get_span_context(), otel_span.parent, parent_context + ) assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" assert sentry_trace_data["span_id"] == "1234567890abcdef" assert sentry_trace_data["parent_span_id"] == "abcdef1234567890" @@ -121,7 +125,9 @@ def test_get_trace_data_with_sentry_trace(): ], ): span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + sentry_trace_data = span_processor._get_trace_data( + otel_span.get_span_context(), otel_span.parent, parent_context + ) assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" assert sentry_trace_data["span_id"] == "1234567890abcdef" assert sentry_trace_data["parent_span_id"] == "abcdef1234567890" @@ -138,7 +144,9 @@ def test_get_trace_data_with_sentry_trace(): ], ): span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + sentry_trace_data = span_processor._get_trace_data( + otel_span.get_span_context(), otel_span.parent, parent_context + ) assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" assert sentry_trace_data["span_id"] == "1234567890abcdef" assert sentry_trace_data["parent_span_id"] == "abcdef1234567890" @@ -175,7 +183,9 @@ def test_get_trace_data_with_sentry_trace_and_baggage(): ], ): span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + sentry_trace_data = span_processor._get_trace_data( + otel_span.get_span_context(), otel_span.parent, parent_context + ) assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" assert sentry_trace_data["span_id"] == "1234567890abcdef" assert sentry_trace_data["parent_span_id"] == "abcdef1234567890"