litellm - ✅(Solved) Fix Bug: OpenTelemetry callback crashes on Usage AI chat due to non-dict `response_obj` [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#24516Fetched 2026-04-08 01:23:07
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Participants
Timeline (top)
cross-referenced ×1referenced ×1

When using the Usage dashboard AI chat feature with OpenTelemetry enabled, the request may complete but the OpenTelemetry success logging path crashes afterward.

The OpenTelemetry integration appears to assume response_obj is always a dict-like object and calls .get(...) on it. In this flow, response_obj can be a list, which causes the logging callback to fail.

There is also a secondary issue where gen_ai.system is sometimes set to None, which OpenTelemetry rejects because attributes must be a supported primitive type.

Error Message

AttributeError: 'list' object has no attribute 'get'

Root Cause

There is also a secondary issue where gen_ai.system is sometimes set to None, which OpenTelemetry rejects because attributes must be a supported primitive type.

Fix Action

Fixed

PR fix notes

PR #24545: fix(opentelemetry): guard against non-dict response_obj in OTEL callbacks

Description (problem / solution / changelog)

Summary

Fixes #24516

The OpenTelemetry integration crashes when response_obj is a non-dict type (e.g. a list), which can happen when using the Usage AI chat feature. The callback assumes response_obj is always dict-like and calls .get() on it, raising AttributeError: 'list' object has no attribute 'get'.

Additionally, gen_ai.system can be set to None when custom_llm_provider is explicitly None in litellm_params, causing Invalid type NoneType for attribute 'gen_ai.system' errors from the OpenTelemetry SDK.

Changes

  • Add isinstance(response_obj, dict) guards before all .get() calls on response_obj in:
    • set_attributes() — response id, model, usage, and choices extraction
    • _record_metrics() — token usage histogram recording
    • _record_time_per_output_token_metric() — completion token extraction
    • _emit_semantic_logs() — per-choice event emission
  • Use or "Unknown" instead of dict .get() default parameter for custom_llm_provider lookups, so that an explicit None value is correctly handled (.get("key", "default") returns None when the key exists with value None)

Test plan

  • Added 5 unit tests in TestOpenTelemetryNonDictResponseObj:
    • test_set_attributes_with_list_response_obj — verifies no crash with list response, fallback ID still set
    • test_set_attributes_with_none_response_obj — verifies no crash with None response
    • test_set_attributes_with_none_provider — verifies gen_ai.system defaults to "Unknown" not None
    • test_record_metrics_with_list_response_obj — verifies duration recorded but token histogram skipped
    • test_record_metrics_with_none_provider — verifies gen_ai.system is "Unknown" in metric attributes
  • All 92 pre-existing tests continue to pass

Changed files

  • litellm/integrations/opentelemetry.py (modified, +31/-13)
  • tests/test_litellm/integrations/test_opentelemetry.py (modified, +115/-0)

Code Example

AttributeError: 'list' object has no attribute 'get'

---

Invalid type NoneType for attribute 'gen_ai.system' value

---

OpenTelemetry logging error in set_attributes 'list' object has no attribute 'get'

---

AttributeError: 'list' object has no attribute 'get'

---

Invalid type NoneType for attribute 'gen_ai.system' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types

---

AttributeError: 'list' object has no attribute 'get'

---

Invalid type NoneType for attribute 'gen_ai.system'
RAW_BUFFERClick to expand / collapse

Summary

When using the Usage dashboard AI chat feature with OpenTelemetry enabled, the request may complete but the OpenTelemetry success logging path crashes afterward.

The OpenTelemetry integration appears to assume response_obj is always a dict-like object and calls .get(...) on it. In this flow, response_obj can be a list, which causes the logging callback to fail.

There is also a secondary issue where gen_ai.system is sometimes set to None, which OpenTelemetry rejects because attributes must be a supported primitive type.

Expected behavior

OpenTelemetry logging should not crash regardless of the shape of response_obj.

If response_obj is not dict-like, the callback should safely skip dict-specific fields or normalize the value before logging.

Actual behavior

The OpenTelemetry callback throws errors such as:

AttributeError: 'list' object has no attribute 'get'

and:

Invalid type NoneType for attribute 'gen_ai.system' value

Example errors

OpenTelemetry logging error in set_attributes 'list' object has no attribute 'get'
AttributeError: 'list' object has no attribute 'get'
Invalid type NoneType for attribute 'gen_ai.system' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types

Relevant code

The installed OpenTelemetry integration appears to assume dict-like responses in multiple places:

  • litellm/integrations/opentelemetry.py

Examples:

  • response_obj.get("id")
  • response_obj.get("model")
  • response_obj.get("usage")
  • response_obj.get("choices", [])

These accesses are not guarded against response_obj being a list.

Why this looks like a bug

The failure is happening in the observability layer, not in the core request handling.

This means:

  • the underlying LiteLLM request may succeed
  • the OpenTelemetry callback then throws while trying to log success metadata

That can create noisy logs and make it look like the request itself failed even when the primary operation was fine.

Reproduction

  1. Enable the opentelemetry callback
  2. Use the Usage dashboard AI chat feature
  3. Send a message
  4. Observe the proxy logs

Result

The logs show OpenTelemetry callback failures such as:

AttributeError: 'list' object has no attribute 'get'

and:

Invalid type NoneType for attribute 'gen_ai.system'

Expected fix

The OpenTelemetry integration should:

  • guard response_obj before calling .get(...)
  • handle list-shaped responses safely
  • default gen_ai.system to a string such as "unknown" instead of None
  • avoid raising callback exceptions for non-critical logging metadata

Notes

This appears to be a non-blocking logging/instrumentation bug, but it can obscure the actual outcome of requests and produce a lot of noise in production logs.

extent analysis

Fix Plan

To resolve the OpenTelemetry logging issue, follow these steps:

  1. Guard response_obj before calling .get(...): Modify the OpenTelemetry integration code in litellm/integrations/opentelemetry.py to check the type of response_obj before attempting to access its attributes.
  2. Handle list-shaped responses safely: Implement a function to safely extract attributes from response_obj, whether it's a dict or a list.
  3. Default gen_ai.system to a string: Set gen_ai.system to a default string value, such as "unknown", when it's None.
  4. Avoid raising callback exceptions: Wrap logging code in try-except blocks to prevent exceptions from being raised for non-critical logging metadata.

Example Code

def safe_get(response_obj, key, default=None):
    """Safely extract an attribute from response_obj."""
    if isinstance(response_obj, dict):
        return response_obj.get(key, default)
    elif isinstance(response_obj, list):
        # Handle list-shaped responses, e.g., return the first element
        return response_obj[0] if response_obj else default
    else:
        return default

# In the OpenTelemetry integration code
response_id = safe_get(response_obj, "id")
response_model = safe_get(response_obj, "model")
response_usage = safe_get(response_obj, "usage")
response_choices = safe_get(response_obj, "choices", [])

# Default gen_ai.system to a string
gen_ai_system = gen_ai.system or "unknown"

try:
    # Logging code here
    # Use safe_get to extract attributes
    # Use gen_ai_system instead of gen_ai.system
except Exception as e:
    # Log the exception, but don't raise it
    print(f"Error logging metadata: {e}")

Verification

To verify the fix, follow these steps:

  1. Enable the opentelemetry callback.
  2. Use the Usage dashboard AI chat feature.
  3. Send a message.
  4. Observe the proxy logs.

The logs should no longer show OpenTelemetry callback failures, and the logging metadata should be correctly extracted and logged.

Extra Tips

  • Regularly review logging code to ensure it's robust and handles unexpected input.
  • Consider adding additional logging or monitoring to detect and report issues like this in the future.
  • Keep the OpenTelemetry integration code up-to-date with the latest best practices and library versions.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

OpenTelemetry logging should not crash regardless of the shape of response_obj.

If response_obj is not dict-like, the callback should safely skip dict-specific fields or normalize the value before logging.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING