Skip to content

TraceState.from_header discards all state when the same key appears across multiple headers, violating W3C spec[ last wins] #5314

@RudraDudhat2509

Description

@RudraDudhat2509

Describe your environment

OS: Windows 11
Python version: 3.12.7
SDK version: 1.42.1
API version: 1.43.0.dev0 (main)

What happened?

TraceState.from_header accepts a list of header strings, since HTTP/1.1 allows the same header to be sent multiple times. However, when the same vendor key appears in two separate headers, the method returns an empty TraceState instead of keeping the last value.

Image

The W3C Trace Context spec (section 3.3.1.1) says:

"If there are duplicate list-members, all but the last MUST be ignored."

The current code applies the single-header duplicate rule (discard everything) to the multi-header case as well.

Steps to Reproduce


result = TraceState.from_header(["vendora=value1", "vendora=value2"])
print(dict(result))  # {}

The same key vendora appears once in each header string, a normal scenario when a proxy splits or re-emits headers.

Expected Result

{"vendora": "value2"}

as Per spec: when the same key appears across multiple headers, the last value wins.

Actual Result

{}
An empty TraceState is returned. All trace context is silently lost.

Additional context

The relevant code is in opentelemetry-api/src/opentelemetry/trace/span.py, lines 409–411: pasting for reference

# duplicate keys are not legal in header
if key in pairs:
    return cls()

The comment is correct for a single header (where duplicates are illegal), but the same branch handles the multi-header case too, where last-wins is the correct behaviour.

This causes silent data loss in production when a proxy or load balancer splits a tracestate header into multiple headers with overlapping keys. Vendors relying on tracestate (Datadog, New Relic, Honeycomb) would lose their metadata entirely with no error or warning logged.

The fix is to overwrite pairs[key] instead of returning early when processing across header, the loop structure already ensures last-header order.

Would you like to implement a fix?

Yes

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions