RuntimeError: dictionary changed size during iteration

这个报错通常出现在 LiteLLM Proxy 并发处理非流式 POST /v1/messages 请求时,成功日志线程与事件循环线程同时读写同一个 metadata 字典。优先排查是否启用了 litellm_settings.cache: true ,以及日志记录(spend row)与响应返回是

快速结论:这个报错通常出现在 LiteLLM Proxy 并发处理非流式 POST /v1/messages 请求时,成功日志线程与事件循环线程同时读写同一个 metadata 字典。优先排查是否启用了 litellm_settings.cache: true,以及日志记录(spend row)与响应返回是否不一致。

适用环境:Issue 中确认的环境为 LiteLLM main 分支 7f437cad5b(pyproject 1.105.0),代理配置使用 Vertex AI 的 vertex_ai/gemini-3.1-flash-image 模型、Redis 缓存(cache: true、cache_params.type: redis)。Issue 未提供操作系统、Python、CUDA、显卡和 PyTorch 版本信息。

最快修复方案:暂无确认的一步修复方案。Issue 指出该竞态已在 main 上由 #46044 和 #47019 修复,并计划随 v1.107.0 发布候选版本提供,可优先尝试升级到包含这两个修复的版本。

注意事项:修复版本在 Issue 关闭时仍为发布候选(release candidate),上线前请自行验证并发场景。该问题具有偶发性,单次请求可能无法复现,不能仅凭一次成功请求判断已修复。

问题场景

用户在 LiteLLM Proxy 上以并发方式发送多个请求,其中包含非流式的 POST /v1/messages 调用。在 24 个并发请求(六种请求类型、两个 worker)的集成测试中,其中 1 个 /v1/messages 请求返回 500,而同一批中的其他 /v1/messages、/v1/chat/completions、/v1/responses 和 /v1/images/generations 均正常返回。报错请求的 spend row 仍记录了正确费用,导致用户为未收到的响应付费。

报错原文

RuntimeError: dictionary changed size during iteration

File "litellm/proxy/anthropic_endpoints/endpoints.py", line 151, in anthropic_response
  result: Final = await base_llm_response_processor.base_process_llm_request(
File "litellm/proxy/common_request_processing.py", line 2649, in _process_llm_request
  responses = await llm_responses
File "litellm/router.py", line 6935, in async_wrapper
  return await self._dispatch_generic_call_type(
...
File "litellm/litellm_core_utils/llm_response_utils/response_metadata.py", line 249, in update_response_metadata
  response_timing_metrics(start_time, end_time, logging_obj, include_overhead)
File "litellm/litellm_core_utils/llm_response_utils/response_metadata.py", line 23, in _timing_window_start
  received_at: Final = get_litellm_metadata_from_kwargs(logging_obj.model_call_details).get("litellm_received_at")
File "litellm/litellm_core_utils/core_helpers.py", line 360, in get_litellm_metadata_from_kwargs
  litellm_metadata = add_missing_spend_metadata_to_litellm_metadata(litellm_metadata, metadata)
File "litellm/litellm_core_utils/core_helpers.py", line 290, in add_missing_spend_metadata_to_litellm_metadata
  for key, value in metadata.items():

原因分析

Issue 根据源码分析给出的原因是:/v1/messages 在同一个 logging 对象上执行了两层嵌套的 @client 包装器。内层包装器先执行 _update_response_metadata,再执行 _dispatch_success_logging;当注册了非内部的同步 success callback 时,handle_sync_success_callbacks_for_async_calls 会把同步 success_handler 提交到日志线程池。启用 litellm_settings.cache: true 后,代理会把字符串 "cache" 放进 litellm.success_callback,而 _remove_internal_custom_logger_callbacks 和 _is_internal_litellm_proxy_callback 都不会过滤普通字符串,因此该线程会在每次异步调用时运行。其 _process_hidden_params_and_response_cost 向 litellm_params["metadata"] 添加 hidden_params 键,与此同时外层包装器的 _update_response_metadata 正在事件循环线程上遍历同一个字典,于是触发 RuntimeError: dictionary changed size during iteration。单层包装器的路由会在 dispatch handler 之前读取 metadata,因此只有 /v1/messages 表现出该问题。

该原因来自 Issue 作者基于源码的推断,评论中也有维护者认可这是根因;但在未包含相关修复的版本上,仍应按“可能原因”对待。

环境排查

  • 确认 LiteLLM 版本是否早于包含 #46044 和 #47019 的版本;Issue 中问题版本为 main at 7f437cad5b(pyproject 1.105.0)。
  • 确认代理配置是否启用了 litellm_settings.cache: true;Issue 中同时使用了 Redis 缓存。
  • 确认是否注册了同步 success callback,尤其是是否出现字符串 "cache" 进入 litellm.success_callback 的情况。
  • 确认复现条件是否涉及并发调用与非流式 /v1/messages;Issue 未提供 Python、CUDA、PyTorch、显卡、操作系统版本,无需据此排查。

解决步骤

  1. 保留当前配置与日志,先按 Issue 的方式用并发请求复现:同时发出 24 个请求,其中包含 POST /v1/messages,观察是否出现 500 和相同 traceback。
  2. 检查代理日志与 spend 记录:确认失败请求是否仍写入含正确费用的 spend row,以判断是否命中该竞态。
  3. 可优先尝试升级到包含 #46044 和 #47019 的 LiteLLM 版本;Issue 提到这两个修复随 v1.107.0 release candidate 提供。升级前请确认目标版本实际包含这两个修复。
  4. 升级后重复并发复现步骤,确认不再出现 RuntimeError: dictionary changed size during iteration。

验证方法

在升级后的环境中再次执行相同并发突发测试,确认所有 /v1/messages 请求均正常返回,且不再出现 500 与该 traceback;同时核对失败请求是否已不再产生“成功”的 spend row。由于问题是偶发的,建议多轮并发测试,而不是只跑一次。

参考来源

BerriAI/litellm #44748

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29344

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注