AttributeError: ‘NoneType’ object has no attribute ‘to_dict’

该报错出现在 RAGFlow 容器处理请求时,底层某对象为 None 却仍被调用 to_dict() ,通常与自定义挂载文件(如 session.py 、提示词或配置模板)或某个依赖服务返回空值有关,优先排查自定义挂载内容与后端日志链路。

快速结论:该报错出现在 RAGFlow 容器处理请求时,底层某对象为 None 却仍被调用 to_dict(),通常与自定义挂载文件(如 session.py、提示词或配置模板)或某个依赖服务返回空值有关,优先排查自定义挂载内容与后端日志链路。

适用环境:RAGFlow infiniflow/ragflow:v0.24.0(配置中同时留有 v0.25.1 注释);Docker Compose 多实例部署;容器内 Python 3.12;启用了 TEI GPU embedding、Sandbox、MySQL/Elasticsearch/Redis/MinIO 外部服务;操作系统、CUDA 版本、显卡型号 Issue 未明确。

最快修复方案:暂无确认的一步修复方案。Issue 未在讨论中给出已验证的修复操作。

注意事项:该 Issue 标签为 question,讨论中作者主要贴出了 Compose 配置与堆栈尾部,未提供完整 traceback 与最终定位结论;以下步骤均为基于现有信息的排查方向,不代表已被验证的修复。

问题场景

用户在 Docker Compose 中以多实例方式部署 RAGFlow v0.24.0,共用同一个外部网络 ragflow-net、共享同一套 MySQL/Elasticsearch/Redis/MinIO 配置。每个实例都额外挂载了自定义文件:service_conf.yaml.templaterelated_question.md 以及覆盖 api/apps/sdk/session.pysession.py。在发起请求时,Quart 请求处理链路抛出未捕获异常,导致请求失败并输出 AttributeError

配置中还启用了 TEI GPU embedding 与 Sandbox,并设置了较激进的并发参数(如 WS=24MAX_CONCURRENT_CHATS=200THREAD_POOL_MAX_WORKERS=1024)。这些都会影响请求路径上不同组件是否返回有效对象。

报错原文

2026-05-15 12:42:16,288 ERROR 13 Unhandled exception during request
Traceback (most recent call last):
  File "/ragflow/.venv/lib/python3.12/site-packages/quart/app.py", line 1500, in full_dispatch_request
    result = await self.dispatch_request(request_context)
  File "/ragflow/.venv/lib/python3.12/site-packages/quart/app.py", line 1597, in dispatch_request
    return await self.ensure_async(handler)(**request_.view_args)
  File "/ragflow/api/apps/init.py", line 177, in wrapper
    return await current_app.ensure_async(func)(*args, **kwargs)
  File "/ragflow/.venv/lib/python3.12/site-packages/quart/utils.py", line 58, in _wrapper
    result = await loop.run_in_executor(
  File "/root/.local/share/uv/python/cpython-3.12.12-linux-x86_64-gnu/lib/python3.12/asyncio/futures.py", line 289, in await
...
AttributeError: 'NoneType' object has no attribute 'to_dict'

注意:Issue 只贴出了堆栈的前半部分,触发 to_dict() 的具体文件与行号并未在讨论中给出,因此无法定位到确切的代码位置。

原因分析

可能原因:某处代码在拿到查询结果或对象后直接调用 .to_dict(),但该对象实际为 None。常见触发场景包括:

  • 请求路径中对数据库(MySQL)、Elasticsearch、Redis 或 MinIO 的查询返回为空,代码未做 None 判断。
  • 自定义挂载的 session.py 覆盖了官方 api/apps/sdk/session.py,其实现与 v0.24.0 内的调用约定不一致,导致上层拿到的对象为 None
  • 多实例共用同一套 RAGFLOW_SECRET_KEY 与后端服务,但服务间数据不同步或某实例先写入、先查询时结果为空。
  • TEI embedding、Sandbox 等外部依赖不可用或被并发参数压垮,返回空结果后继续走入序列化逻辑。

注意:以上均为基于堆栈与配置的推断,Issue 讨论中未给出确认结论。

环境排查

  • 确认实际运行的镜像版本:配置里 v0.24.0 生效,v0.25.1 仅为注释,排查时不要误按 v0.25.1 判断行为。
  • 确认容器内 Python 版本为 3.12(堆栈显示 3.12.12),以及 RAGFlow 自身的 venv 依赖是否与镜像自带一致。
  • 确认自定义挂载文件的内容与来源:service_conf.yaml.templatecustom/related_question.mdcustom/session.py,尤其是 session.py 是否针对 v0.24.0 编写。
  • 确认 MySQL、Elasticsearch、Redis、MinIO 四个后端服务都处于健康状态,且三个 RAGFlow 实例连接的是同一组服务。
  • 确认 TEI GPU embedding 服务(ragflow-tei-gpu)可访问,模型 Qwen/Qwen3-Embedding-0.6B 已正常加载。
  • 确认 Sandbox(ragflow-sandbox-executor-manager:9385)容器已启动并可被 RAGFlow 实例访问。
  • 确认外部网络 ragflow-net 已由 docker-compose-shared.yml 创建,三个实例的容器名与配置中的主机名一致。
  • 确认并发参数(WS=24MAX_CONCURRENT_CHATS=200THREAD_POOL_MAX_WORKERS=1024)没有超过宿主机资源承载能力。
  • CUDA、显卡型号、宿主机操作系统:Issue 未提供,需要自行确认。

解决步骤

  1. 先拿到完整 traceback。当前 Issue 只贴出堆栈前半段,需在容器日志中查找 AttributeError: 'NoneType' object has no attribute 'to_dict' 所在的具体文件和行号。可查看 ./ragflow-1-logs(以及 -2、-3)下的日志文件,或在 docker logs ragflow-instance-1 中检索该异常。
  2. 根据完整堆栈定位是第一方代码还是自定义覆盖文件。如果栈中出现 /ragflow/api/apps/sdk/session.py,需重点核对 ./custom/session.py 与 v0.24.0 原始文件之间的差异。
  3. 临时回退自定义挂载做对照验证(可优先尝试):把 ./custom/session.py 从 volumes 中移除,恢复官方 session.py,重建容器后复现同一请求,看异常是否消失。若消失,即可确认与自定义代码有关;若仍存在,则继续排查后端服务。
  4. 按相同思路逐一排查其他自定义挂载:service_conf.yaml.templaterelated_question.md 是否为当前版本所支持的内容格式。
  5. 检查后端服务返回空值的路径:确认 MySQL 中对应的库表数据是否存在、Elasticsearch 索引是否正常、Redis 是否被清空或连接失败、MinIO 中对象是否可见。
  6. 检查 TEI embedding 与 Sandbox 依赖:确认这两个服务的连通性和响应状态,避免在请求链路上返回空结果。
  7. 若在多实例并发下更易复现,可临时降低并发做二分验证:例如调小 WSMAX_CONCURRENT_CHATSMAX_CONCURRENT_TASKSTHREAD_POOL_MAX_WORKERS,观察异常是否仍出现。
  8. 如果问题稳定复现且无法定位,建议在 Issue 中补充完整 traceback、触发请求的入口(Web UI/API)、以及是否使用了自定义 session.py,便于社区进一步定位。

验证方法

在完成上述任一步骤后,重新执行之前触发异常的同一请求:

  • 若请求正常返回,且对应容器日志中不再出现 Unhandled exception during requestAttributeError: 'NoneType' object has no attribute 'to_dict',可判断该路径已恢复。
  • 若仅在回退自定义 session.py 后恢复,则需继续修正自定义代码中的空值判断,而不是长期依赖回退。
  • 若异常仍存在,说明触发点在别处,需回到完整 traceback 继续定位。

参考来源

infiniflow/ragflow #14949

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 23964

发表回复

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