Skip to content

get_propagated_context() ignores standard W3C traceparent and baggage headers on FastAPI requests unless Google-Agent-Engine-Traceparent is set #7844

Closed

Description

@juliays

🔴 Required Information

Describe the Bug:
AdkWebServer.get_fast_api_app() (src/google/adk/cli/fast_api.py) installs a @app.middleware("http") hook (context_propagation) that calls get_propagated_context(request) (src/google/adk/telemetry/_agent_engine.py:59-84) and attaches the returned OpenTelemetry context for the duration of the request.

#4767 and #4972 were closed on the assumption that this middleware extracts inbound W3C traceparent headers so adk api_server / adk web continues the caller's distributed trace. However, get_propagated_context() only runs TraceContextTextMapPropagator().extract(...) on the proprietary Google-Agent-Engine-Traceparent header:

# src/google/adk/telemetry/_agent_engine.py:59-84
def get_propagated_context(request: fastapi.Request) -> context.Context:
  """Propagates context from the request headers."""
  ctx = context.get_current()

  if _GOOGLE_TRACEPARENT_HEADER in request.headers:
    original_traceparent = request.headers[_GOOGLE_TRACEPARENT_HEADER]
    ctx = baggage.set_baggage(
        _GOOGLE_TRACEPARENT_BAGGAGE_KEY,
        original_traceparent,
        context=ctx,
    )

  if _GOOGLE_AE_TRACEPARENT_HEADER in request.headers:
    ae_traceparent = request.headers[_GOOGLE_AE_TRACEPARENT_HEADER]
    extracted_ctx = tracecontext.TraceContextTextMapPropagator().extract(
        carrier={"traceparent": ae_traceparent}, context=ctx
    )
    if extracted_ctx is not ctx:
      ctx = baggage.set_baggage(
          _TRACEPARENT_BAGGAGE_KEY, ae_traceparent, context=extracted_ctx
      )

  return ctx

As a result, when any non-Agent-Engine caller (an API gateway, load balancer, or upstream microservice) sends a standard W3C traceparent (and/or baggage) header to get_fast_api_app():

  1. traceparent is only stashed in baggage under "google_traceparent" (which TopSpanProcessor reads to stamp supportID), never extracted as the parent SpanContext. Every inbound /run or /run_sse request starts a brand-new root trace ID instead of parenting under the caller's span.
  2. Inbound W3C baggage headers (e.g., tenant, experiment, or evaluation metadata) are not extracted at all.

Steps to Reproduce:

  1. Create a FastAPI app via get_fast_api_app(...) with an active TracerProvider and InMemorySpanExporter.
  2. Send a POST request to /run with a valid W3C header:
    traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
    and baggage: tenant_id=acme.
  3. Inspect the exported invocation / invoke_agent spans.

Expected Behavior:

  • When Google-Agent-Engine-Traceparent is present, it continues to take precedence as the extracted parent span context (preserving Vertex Agent Engine supportID behavior).
  • When Google-Agent-Engine-Traceparent is absent and a standard W3C traceparent header is present, get_propagated_context() extracts traceparent (and tracestate) as the parent SpanContext so ADK spans join the caller's trace (trace_id == 0x4bf92f3577b34da6a3ce929d0e0e4736).
  • Inbound W3C baggage headers are extracted via W3CBaggagePropagator without clobbering the internal google_traceparent / traceparent baggage keys.

Observed Behavior:
The exported ADK spans have a newly generated trace_id unrelated to 4bf92f3577b34da6a3ce929d0e0e4736, and inbound W3C baggage entries are dropped.

Environment Details:

  • ADK Library Version: main (2.13.0+)
  • Desktop OS: macOS / Linux
  • Python Version: 3.11+

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: N/A (telemetry / FastAPI middleware layer)

🟡 Optional Information

Regression:
#4767 reported this gap and #4972 was closed assuming commit ffa057c1 resolved it via get_propagated_context, but get_propagated_context only extracts Google-Agent-Engine-Traceparent.

Minimal Reproduction Code:

from fastapi import FastAPI, Request
from fastapi.testclient import TestClient
from opentelemetry import baggage, trace
from google.adk.telemetry._agent_engine import get_propagated_context

app = FastAPI()

@app.get("/test")
def endpoint(request: Request):
  ctx = get_propagated_context(request)
  span_ctx = trace.get_current_span(ctx).get_span_context()
  return {
      "trace_id": f"{span_ctx.trace_id:032x}",
      "tenant": baggage.get_baggage("tenant_id", context=ctx),
  }

client = TestClient(app)
resp = client.get(
    "/test",
    headers={
        "traceparent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
        "baggage": "tenant_id=acme",
    },
)
# Returns trace_id="00000000000000000000000000000000" and tenant=None
print(resp.json())

How often has this issue occurred?:

  • Always (100%)

Activity

  1. added a commit that references this issue on Nov 3, 2026
    f27b8f1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions