fix(proxy): let the OTel trace id fallback fill a null litellm_trace_id

A body that serializes litellm_trace_id as null or an empty string carries no identity, so it must not
block the server span fallback. Also mark the nested metadata write as an out-param store

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-09-16 07:48:58 +00:00
parent 49417d4fa2
commit 4cb4493fa7
2 changed files with 19 additions and 2 deletions

View file

@ -121,7 +121,7 @@ def _trace_id_from_otel_span(span: "OtelSpan | None") -> str | None:
def add_otel_trace_id_to_request(
data: dict[str, object], _metadata_variable_name: str, parent_otel_span: "OtelSpan | None"
) -> None:
if "litellm_trace_id" in data:
if data.get("litellm_trace_id"):
return
metadata: Final = data.get(_metadata_variable_name)
if isinstance(metadata, dict) and metadata.get("trace_id"):
@ -131,7 +131,7 @@ def add_otel_trace_id_to_request(
return
data["litellm_trace_id"] = trace_id # rebind-ok: data is an out-param
if isinstance(metadata, dict):
metadata["trace_id"] = trace_id
metadata["trace_id"] = trace_id # rebind-ok: metadata is the request's own out-param dict
def _session_id_from_baggage(baggage: str) -> str | None:

View file

@ -3605,6 +3605,23 @@ async def test_add_litellm_data_to_request_otel_span_does_not_override_caller_tr
assert from_body["metadata"]["trace_id"] == "body-trace"
@pytest.mark.asyncio
@pytest.mark.parametrize("empty_trace_id", [None, ""])
async def test_add_litellm_data_to_request_otel_span_fills_empty_body_trace_id(empty_trace_id):
"""A serialized-but-empty litellm_trace_id in the body (null or "") carries
no identity, so it must not block the OTel server span fallback."""
otel_trace_id = 0x4BF92F3577B34DA6A3CE929D0E0E4736
data = await add_litellm_data_to_request(
data={"model": "gpt-5.6", "litellm_trace_id": empty_trace_id},
request=_request_mock_without_trace_headers(),
user_api_key_dict=UserAPIKeyAuth(api_key="hashed-key", parent_otel_span=_otel_span_with_trace_id(otel_trace_id)),
proxy_config=MagicMock(),
general_settings={},
)
assert data["litellm_trace_id"] == format(otel_trace_id, "032x")
assert data["metadata"]["trace_id"] == format(otel_trace_id, "032x")
@pytest.mark.asyncio
@pytest.mark.parametrize("parent_otel_span", [None, "invalid_span", "not_a_span"])
async def test_add_litellm_data_to_request_no_trace_id_without_valid_otel_span(parent_otel_span):