#41591·litellm

[Bug]: OTel v2: gen_ai.output.messages and gen_ai.response.finish_reasons missing on Responses API (/v1/responses) spans

Author: asoriano-stratioCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbugproxy

Check for existing issues

  • I have searched the existing issues and checked that my issue is not a duplicate.

What happened?

With LITELLM_OTEL_V2=true and OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=span_only, the chat span for a /v1/responses request carries gen_ai.input.messages, usage and cost, but neither gen_ai.output.messages nor gen_ai.response.finish_reasons.

The same request through /v1/chat/completions has both.

User Flow

Root cause: litellm/integrations/otel/model/payloads.py, LLMCallSpanData.from_standard_logging_payload, reads only payload["response"]["choices"] (choices_out = _dicts(response.get("choices")), finish_reasons = _finish_reasons(choices_out)). For call_type in ("responses", "aresponses") the payload response is ResponsesAPIResponse.model_dump(): it has output (message / function_call / reasoning items), status and incomplete_details, but no choices, so GenAIMapper returns None for both attributes and they are dropped. The Weave and Langtrace mappers lose the output through the same choices_out field.

The legacy v1 integration handles this (integrations/opentelemetry.py, _transform_responses_api_output_to_otel, added for #25840 in c0da139), but the fix was never ported to v2 and is still missing on main.

Proposed fix: in from_standard_logging_payload, when choices is absent and output is a list, synthesize one choice: message items → assistant content from output_text parts; function_call items → tool_calls (call_id, name, arguments); finish_reason from status / incomplete_details (completed → stop / tool_calls, incomplete + max_output_tokens → length, content_filter → content_filter). Alternatively build on model/request_io.response_output, which already knows the ResponsesAPIResponse shape. Happy to send a PR.

Proof the bug occurs

proxy with litellm_settings.callbacks: [otel], OTEL_EXPORTER=console; POST /v1/responses {"model": "", "input": "Say hi"}; inspect the printed span.

What part of LiteLLM is this about?

Proxy

What LiteLLM version are you on ?

1.101.0

Twitter / LinkedIn details

No response