fix(proxy): ignore non-span parent_otel_span when deriving litellm_trace_id

UserAPIKeyAuth.parent_otel_span is Any at runtime (opentelemetry is an optional extra), so the OTel
trace-id fallback must only format an int trace id, otherwise an object that merely quacks like a span
turns the whole request into a 500

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

View file

@ -112,9 +112,10 @@ def _trace_id_from_otel_span(span: "OtelSpan | None") -> str | None:
if span is None:
return None
span_context: Final = span.get_span_context()
if not span_context.is_valid:
trace_id: Final = span_context.trace_id
if not span_context.is_valid or not isinstance(trace_id, int):
return None
return format(span_context.trace_id, "032x")
return format(trace_id, "032x")
def add_otel_trace_id_to_request(

View file

@ -3606,11 +3606,12 @@ async def test_add_litellm_data_to_request_otel_span_does_not_override_caller_tr
@pytest.mark.asyncio
@pytest.mark.parametrize("parent_otel_span", [None, "invalid_span"])
@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):
"""No OTel span (OTel off) or a span with an invalid context must leave
litellm_trace_id unset so downstream keeps generating its own id."""
span = INVALID_SPAN if parent_otel_span == "invalid_span" else None
"""No OTel span (OTel off), a span with an invalid context, or an object
that only quacks like a span (auth is typed loosely and often stubbed) must
leave litellm_trace_id unset so downstream keeps generating its own id."""
span = {"invalid_span": INVALID_SPAN, "not_a_span": MagicMock()}.get(parent_otel_span)
data = await add_litellm_data_to_request(
data={"model": "gpt-5.6"},
request=_request_mock_without_trace_headers(),