快速结论:这个报错通常出现在 LiteLLM Proxy 开启 callbacks: ["otel"] 并对 MCP 工具调用(tools/call 或 tools/list)做追踪时:set_attributes 对 response_obj 直接调用 .get(),但实际对象是 Pydantic 的 CallToolResult(或是 list),从而抛出 AttributeError。优先排查 span 输出路径是否对非 dict 响应类型做了保护。
适用环境:LiteLLM Proxy,已在 v1.83.14、v1.85.0、v1.88.0、v1.89.0 复现;评论中进一步确认在 v1.99.0、v1.100.0 / v1.101.0 / v1.102.0、v1.104.2、v1.104.3、v1.105.0 以及 v1.106.0-rc.1 仍未修复。使用 litellm_settings.callbacks: ["otel"] 并注册 MCP server(评论中使用 stdio MCP server 与多个 HTTP MCP server)。未提供 CUDA / 显卡相关信息。
最快修复方案:暂无确认的一步修复方案。Issue 中提出的 getattr / hasattr 保护(PR #30660)已合并但从未进入 main,并在所有已发布版本中缺失;评论指出当前唯一被验证“有效”的做法是:当 response_obj 不含 .get 时视作“没有 LLM response 字段”,即加 getattr/hasattr 保护。
注意事项:报错本身被 set_attributes 内部捕获,只记录为 “OpenTelemetry logging error in set_attributes”,span 仍会发出,但写入 output 的代码不会执行,导致工具输出静默丢失。仅针对 CallToolResult 做特殊处理(如 #30671)无法覆盖 tools/list 传入 list 的场景,需同时处理。
问题场景
在 LiteLLM Proxy 中注册 MCP server(mcp_servers 块),并设置 litellm_settings.callbacks: ["otel"] 配合 OTLP endpoint 后,调用任意 MCP 工具(直接 /mcp 的 tools/call,或 chat-completions 的 MCP 自动执行)即触发。Issue 正文给出了最小进程内复现:直接构造 CallToolResult 并调用 async_success_handler,即可复现 AttributeError。评论中补充第二类触发场景:MCP 的 list_tools 会把一个普通 list 作为 response_obj 传入,每次 tools/list 也会报同一行错误。
报错原文
OpenTelemetry logging error in set_attributes 'CallToolResult' object has no attribute 'get'
File ".../litellm/integrations/opentelemetry.py", line 2234, in set_attributes
raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')
AttributeError: 'CallToolResult' object has no attribute 'get'
LiteLLM:ERROR: opentelemetry.py:2690 - OpenTelemetry logging error in set_attributes 'list' object has no attribute 'get'
Traceback (most recent call last):
File "/app/.venv/lib/python3.13/site-packages/litellm/integrations/opentelemetry.py", line 2476, in set_attributes
response_id = (response_obj.get("id") if response_obj else None) or standard_logging_payload.get("id")
^^^^^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'get'
原因分析
最可能的原因是 litellm/integrations/opentelemetry.py 的 set_attributes 中直接假设 response_obj 是 dict:
response_id = (response_obj.get("id") if response_obj else None) or standard_logging_payload.get("id")
但当追踪对象是 MCP 工具调用时,response_obj 实际是 Pydantic 的 mcp.types.CallToolResult,不提供 .get(),于是在设置任何 output / response 属性之前就抛出异常。异常被捕获并记录为 “OpenTelemetry logging error in set_attributes”,因此 span 仍会发出,并保留输入属性 mcp_tool_call_metadata,但写入工具输出(如期望的 gen_ai.tool.output)的代码不会执行,输出静默缺失。
评论进一步确认:list_mcp_tools 传入的是普通 list,同样没有 .get,命中的是同一行代码;因此仅特判 CallToolResult 的修复不完整。
此外,评论指出 PR #30660(commit 0b5485ee)虽然显示已合并并自动关闭了本 Issue,但该 commit 不在 main 的历史中:gh api repos/BerriAI/litellm/compare/0b5485ee...main 返回 "diverged" 且 behind_by 为 15,怀疑 main 在该批次合并后被重写。结果是没有一个已发布版本包含该保护逻辑。
环境排查
- 确认 LiteLLM 版本:Issue 正文在 v1.88.0 / v1.89.0 复现,也在 v1.83.14 / v1.85.0 出现;评论确认 v1.99.0、v1.100.0 / v1.101.0 / v1.102.0、v1.104.2、v1.104.3、v1.105.0、v1.106.0-rc.1 仍未修复。
- 确认是否配置了
litellm_settings.callbacks: ["otel"]及 OTLP endpoint。 - 确认是否注册了 MCP server(评论中使用 stdio MCP server 与多个 HTTP MCP server)。
- 检查
litellm/integrations/opentelemetry.py中set_attributes是否仍存在未保护的response_obj.get("id")。评论给出的定位:v1.99.0 在第 2445 行,v1.100.0 / v1.101.0 / v1.102.0 在第 2476 行,v1.103.0-rc.1 / main 在第 2509 行(具体行号随版本略有差异)。 - 确认 MCP 调用类型:
tools/call触发CallToolResult路径,tools/list触发list路径,两者需分别验证。 - Issue 未提供 CUDA、显卡、Python 版本(评论中出现 Python 3.13 的 traceback 路径),这些不在本 Issue 的确证范围内。
解决步骤
- 先在本地确认触发路径:开启 otel callback、注册 MCP server 后分别调用
tools/call与tools/list,观察 proxy 日志中是否出现 “OpenTelemetry logging error in set_attributes” 及对应的AttributeError。 - 定位
litellm/integrations/opentelemetry.py的set_attributes,找到response_id = (response_obj.get("id") if response_obj else None) or standard_logging_payload.get("id")这一行。 - 如确认代码未修复,可优先尝试在本地打补丁,采用 Issue 与评论一致的方向:对非 dict、无
.get的response_obj使用getattr/hasattr保护。Issue 正文示例:response_id = ( (response_obj.get("id") if isinstance(response_obj, dict) else getattr(response_obj, "id", None)) if response_obj else None ) or standard_logging_payload.get("id")该保护需同时覆盖
CallToolResult与list两种形态;评论指出hasattr(response_obj, "get")可一次覆盖两者。 - 若需要把工具输出写入 span,另需将
CallToolResult.content提取到工具输出属性(Issue 中建议对应gen_ai.tool.output)。此部分 Issue 未给出已验证实现,属于期望行为。 - 不要依赖 PR #30660 的已合并状态:评论明确说明该 commit
0b5485ee不在main历史中,且在所有已发布 tag 中都不存在保护注释,需确认升级后的镜像实际代码。 - 重新构建 / 部署打补丁后的镜像,替换 proxy 镜像(评论中使用的镜像是
ghcr.io/berriai/litellm:v1.102.0,可作为环境参照)。
验证方法
再次通过 proxy 调用 MCP 的 tools/call 与 tools/list,确认日志中不再出现 OpenTelemetry logging error in set_attributes 以及 'CallToolResult' object has no attribute 'get' / 'list' object has no attribute 'get'。同时检查导出的 span:评论表示打上保护后,span 可正常导出并带有 litellm.call_id,错误停止。若还需验证工具输出是否写入 span,应确认 span 中除输入属性 mcp_tool_call_metadata 外,是否包含对应的工具输出属性(如 gen_ai.tool.output)。
参考来源
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。

![[Bug] Embedded chatbot drops numeric zero defaults and required number values](https://www.chat-gpts.plus/wp-content/uploads/2026/10/43242-e549e47a-768x403.jpg)
