diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index 4a3dbefddd5..af6ec53cc8e 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -6,6 +6,10 @@ Notes](../../RELEASENOTES.md). ## Unreleased +* Fixed `TraceContextPropagator` to normalize empty `tracestate` header values + to `null` when extracting trace context. + ([#7407](https://github.com/open-telemetry/opentelemetry-dotnet/pull/7407)) + ## 1.16.0 Released 2026-Jun-10 diff --git a/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs index 6561c0ab459..49554de17cb 100644 --- a/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs +++ b/src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs @@ -69,8 +69,8 @@ public override PropagationContext Extract(PropagationContext context, T carr } string? tracestate = null; - TryExtractTracestate(getter(carrier, TraceState), out var extractedTracestate, out var hasTraceState); - if (hasTraceState) + var extracted = TryExtractTracestate(getter(carrier, TraceState), out var extractedTracestate, out var hasTraceState); + if (hasTraceState && (!extracted || extractedTracestate.Length > 0)) { tracestate = extractedTracestate; } diff --git a/test/OpenTelemetry.Tests/Trace/Propagation/TraceContextPropagatorTests.cs b/test/OpenTelemetry.Tests/Trace/Propagation/TraceContextPropagatorTests.cs index 9e96e0ded8e..8942cd1e244 100644 --- a/test/OpenTelemetry.Tests/Trace/Propagation/TraceContextPropagatorTests.cs +++ b/test/OpenTelemetry.Tests/Trace/Propagation/TraceContextPropagatorTests.cs @@ -154,6 +154,24 @@ public void TracestateToStringEmpty() Assert.Null(context.ActivityContext.TraceState); } + [Theory] + [InlineData("")] + [InlineData(" ")] + [InlineData(" , ")] + public void TracestateToStringEmptyHeaderValue(string traceState) + { + var headers = new Dictionary + { + { TraceParent, $"00-{TraceId}-{SpanId}-01" }, + { TraceState, traceState }, + }; + + var propagator = new TraceContextPropagator(); + var context = propagator.Extract(default, headers, Getter); + + Assert.Null(context.ActivityContext.TraceState); + } + [Fact] public void TracestateToString() {