From e8f8aceada8180b99d8f730887af1a71e4b38e0a Mon Sep 17 00:00:00 2001 From: Safal Gupta <148842438+alphasafal@users.noreply.github.com> Date: Sun, 25 Oct 2026 18:23:19 +0000 Subject: [PATCH 1/4] fix(tracing): drop trailing comma when serializing baggage without third-party items Baggage.serialize(include_third_party=True) appended third_party_items unconditionally, so when there were no third-party items it added an empty segment and the serialized header ended with a comma (e.g. "sentry-trace_id=...,sentry-public_key=...,"). This is reachable from the Celery integration, which calls combined.serialize(include_third_party=True) whenever the merged baggage has only Sentry items. Only append third_party_items when it is non-empty; the output is unchanged when third-party items are present. Adds a regression test. --- sentry_sdk/tracing_utils.py | 2 +- tests/tracing/test_baggage.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index 8a6961ba15..2ac3a67e4b 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -973,7 +973,7 @@ def serialize(self, include_third_party: bool = False) -> str: item = Baggage.SENTRY_PREFIX + quote(key) + "=" + quote(str(val)) items.append(item) - if include_third_party: + if include_third_party and self.third_party_items: items.append(self.third_party_items) return ",".join(items) diff --git a/tests/tracing/test_baggage.py b/tests/tracing/test_baggage.py index 1e0075feaa..1f06ed0275 100644 --- a/tests/tracing/test_baggage.py +++ b/tests/tracing/test_baggage.py @@ -67,6 +67,30 @@ def test_mixed_baggage(): ) +def test_serialize_no_trailing_comma_without_third_party_items(): + # With Sentry items but no third-party items, include_third_party=True must not + # append an empty segment, which would leave a trailing comma in the header. + header = ( + "sentry-trace_id=771a43a4192642f0b136d5159a501700," + "sentry-public_key=49d0f7386ad645858ae85020e393bef3," + "sentry-sample_rate=0.01337" + ) + baggage = Baggage.from_incoming_header(header) + + assert baggage.third_party_items == "" + + serialized = baggage.serialize(include_third_party=True) + + assert not serialized.endswith(",") + # with no third-party items, include_third_party should change nothing + assert serialized == baggage.serialize() + assert serialized == ( + "sentry-trace_id=771a43a4192642f0b136d5159a501700," + "sentry-public_key=49d0f7386ad645858ae85020e393bef3," + "sentry-sample_rate=0.01337" + ) + + def test_malformed_baggage(): header = "," From 0bc5679eb931bfebde77d4ced83d20de9e6d7f58 Mon Sep 17 00:00:00 2001 From: Safal Gupta <148842438+alphasafal@users.noreply.github.com> Date: Tue, 27 Oct 2026 09:05:47 +0530 Subject: [PATCH 2/4] test(celery): cover baggage propagation without third-party items Adds a Celery header test where the incoming baggage has only Sentry items. The outgoing baggage must not end with a trailing comma. --- .../celery/test_update_celery_task_headers.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/integrations/celery/test_update_celery_task_headers.py b/tests/integrations/celery/test_update_celery_task_headers.py index 18f2f96bbf..0afebc7b98 100644 --- a/tests/integrations/celery/test_update_celery_task_headers.py +++ b/tests/integrations/celery/test_update_celery_task_headers.py @@ -15,6 +15,12 @@ "custom=value" ) +SENTRY_ONLY_BAGGAGE_VALUE = ( + "sentry-trace_id=771a43a4192642f0b136d5159a501700," + "sentry-public_key=49d0f7386ad645858ae85020e393bef3," + "sentry-sample_rate=0.1337" +) + SENTRY_TRACE_VALUE = "771a43a4192642f0b136d5159a501700-1234567890abcdef-1" @@ -124,6 +130,28 @@ def test_span_with_transaction_custom_headers(sentry_init): ) +def test_span_with_transaction_custom_headers_without_third_party_baggage( + sentry_init, +): + sentry_init(traces_sample_rate=1.0) + headers = { + "baggage": SENTRY_ONLY_BAGGAGE_VALUE, + "sentry-trace": SENTRY_TRACE_VALUE, + } + + with sentry_sdk.start_transaction(name="test_transaction"): + with sentry_sdk.start_span(op="test_span") as span: + outgoing_headers = _update_celery_task_headers(headers, span, False) + + for baggage in ( + outgoing_headers["baggage"], + outgoing_headers["headers"]["baggage"], + ): + assert baggage.startswith("sentry-") + assert not baggage.endswith(",") + assert "custom=" not in baggage + + @pytest.mark.parametrize("monitor_beat_tasks", [True, False]) def test_celery_trace_propagation_default(sentry_init, monitor_beat_tasks): """ From 1f53399d70cf9ea96e6b40bd37a36ac2beb25070 Mon Sep 17 00:00:00 2001 From: Safal Gupta <148842438+alphasafal@users.noreply.github.com> Date: Wed, 28 Oct 2026 15:36:47 +0530 Subject: [PATCH 3/4] test(tracing): simplify baggage regression coverage --- .../celery/test_update_celery_task_headers.py | 28 ------------------- tests/tracing/test_baggage.py | 5 +--- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/tests/integrations/celery/test_update_celery_task_headers.py b/tests/integrations/celery/test_update_celery_task_headers.py index 0afebc7b98..18f2f96bbf 100644 --- a/tests/integrations/celery/test_update_celery_task_headers.py +++ b/tests/integrations/celery/test_update_celery_task_headers.py @@ -15,12 +15,6 @@ "custom=value" ) -SENTRY_ONLY_BAGGAGE_VALUE = ( - "sentry-trace_id=771a43a4192642f0b136d5159a501700," - "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=0.1337" -) - SENTRY_TRACE_VALUE = "771a43a4192642f0b136d5159a501700-1234567890abcdef-1" @@ -130,28 +124,6 @@ def test_span_with_transaction_custom_headers(sentry_init): ) -def test_span_with_transaction_custom_headers_without_third_party_baggage( - sentry_init, -): - sentry_init(traces_sample_rate=1.0) - headers = { - "baggage": SENTRY_ONLY_BAGGAGE_VALUE, - "sentry-trace": SENTRY_TRACE_VALUE, - } - - with sentry_sdk.start_transaction(name="test_transaction"): - with sentry_sdk.start_span(op="test_span") as span: - outgoing_headers = _update_celery_task_headers(headers, span, False) - - for baggage in ( - outgoing_headers["baggage"], - outgoing_headers["headers"]["baggage"], - ): - assert baggage.startswith("sentry-") - assert not baggage.endswith(",") - assert "custom=" not in baggage - - @pytest.mark.parametrize("monitor_beat_tasks", [True, False]) def test_celery_trace_propagation_default(sentry_init, monitor_beat_tasks): """ diff --git a/tests/tracing/test_baggage.py b/tests/tracing/test_baggage.py index 1f06ed0275..3d70a7cfea 100644 --- a/tests/tracing/test_baggage.py +++ b/tests/tracing/test_baggage.py @@ -67,9 +67,7 @@ def test_mixed_baggage(): ) -def test_serialize_no_trailing_comma_without_third_party_items(): - # With Sentry items but no third-party items, include_third_party=True must not - # append an empty segment, which would leave a trailing comma in the header. +def test_sentry_only_baggage(): header = ( "sentry-trace_id=771a43a4192642f0b136d5159a501700," "sentry-public_key=49d0f7386ad645858ae85020e393bef3," @@ -81,7 +79,6 @@ def test_serialize_no_trailing_comma_without_third_party_items(): serialized = baggage.serialize(include_third_party=True) - assert not serialized.endswith(",") # with no third-party items, include_third_party should change nothing assert serialized == baggage.serialize() assert serialized == ( From b6fb51daf3ca2798f29831e0024ea6871964b4be Mon Sep 17 00:00:00 2001 From: Safal Gupta <148842438+alphasafal@users.noreply.github.com> Date: Wed, 28 Oct 2026 15:48:59 +0530 Subject: [PATCH 4/4] test(tracing): update baggage repr expectations without trailing comma --- tests/test_tracing_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_tracing_utils.py b/tests/test_tracing_utils.py index 3098e73667..293d83b43f 100644 --- a/tests/test_tracing_utils.py +++ b/tests/test_tracing_utils.py @@ -133,11 +133,11 @@ def test_strip_sentry_baggage(header, expected): (Baggage(sentry_items={}, mutable=False), ''), ( Baggage(sentry_items={"foo": "bar"}), - '', + '', ), ( Baggage(sentry_items={"foo": "bar"}, mutable=False), - '', + '', ), ( Baggage(sentry_items={"foo": "bar"}, third_party_items="asdf=1234,"),