issue: deleting chats leaves dangling chat_file links, orphaned file rows, and leaked uploads on disk

在 Open WebUI 中永久删除带附件的聊天后,数据库里的 chat_file 关联行、孤立的 file 记录、磁盘上的上传文件以及对应的向量集合不会被清理,长期运行会导致 uploads/ 目录和向量库持续膨胀。优先排查 SQLite 部署下外键是否未生效,以及删除流程是否遗漏了对 file

快速结论:在 Open WebUI 中永久删除带附件的聊天后,数据库里的 chat_file 关联行、孤立的 file 记录、磁盘上的上传文件以及对应的向量集合不会被清理,长期运行会导致 uploads/ 目录和向量库持续膨胀。优先排查 SQLite 部署下外键是否未生效,以及删除流程是否遗漏了对 file 与磁盘数据的回收逻辑。

适用环境:Open WebUI v0.11.3(在 dev 分支 commit 420b4a2797fa283cd15b5ee267380743115eca5f 上同样复现);Docker 安装;操作系统 Debian 13(Docker 容器)/ Linux x86_64;与浏览器无关。

最快修复方案:暂无确认的一步修复方案。Issue 中记录了根因位置与验证方法,但未给出经验证的补丁或升级版本,需等待官方修复或按下文手动清理。

注意事项:手动清理数据库与磁盘文件存在删错数据的风险,操作前务必先备份数据库和 uploads/ 目录;同时不要假设 PostgreSQL 部署就完全正常,Issue 指出即便外键生效,也缺少判断 file 是否还有其他所有者(chat_file、knowledge_file、channel_file)后再回收的逻辑。

问题场景

使用 Open WebUI(v0.11.3 或任意 v0.11.x 版本,Docker + SQLite 默认部署)创建聊天并上传附件(图片或文档),然后通过 UI 或 API(DELETE /api/v1/chats/{id})永久删除该聊天。删除后再次检查数据库与磁盘时会发现:chat 行已消失,但 chat_file 行仍然存在并指向不存在的 chat_id,file 行依然孤立存在,/app/backend/data/uploads/ 下的物理文件也未被删除。该问题出现在 delete_chat_by_id、delete_chat_by_id_and_user_id、delete_chats_by_user_id、delete_chats_by_user_id_and_folder_id 等删除路径上。

报错原文

issue: deleting chats leaves dangling chat_file links, orphaned file rows, and leaked uploads on disk

-- The chat row is gone:
SELECT * FROM chat WHERE id = '<chat_id>'; -- 0 rows

-- But the chat_file row is still present:
SELECT * FROM chat_file WHERE chat_id = '<chat_id>'; -- 1 row (dangling link!)

-- The file row is still present:
SELECT * FROM file WHERE id = '<file_id>'; -- 1 row (orphaned!)

原因分析

最可能的原因有三层,均来自 Issue 正文的代码定位:

  • 数据库关联未级联删除:在 SQLite 部署下,数据库连接未启用 PRAGMA foreign_keys(见 internal/db.py),因此 models/chats.py:223 中定义在 ChatFile.chat_id 上的 ON DELETE CASCADE 不会在删除 Chat 行时触发,chat_file 行会一直残留并指向不存在的 chat ID。
  • 孤立 file 记录无回收逻辑:即便外键生效,或在 PostgreSQL 上,删除聊天也只移除 chat_file 链接,没有逻辑去检查被引用的 file 行是否还被其他所有者(chat_file、knowledge_file、channel_file)使用,导致 file 表出现孤立行。
  • 物理与向量存储泄漏:由于 file 行从未被删除,Storage.delete_file(file.path) 与 ASYNC_VECTOR_DB_CLIENT.delete(collection_name=f"file-{file_id}") 从未被调用,上传文件永久留在磁盘上。

Issue 提到生产服务器审计结果为:残留 78 条 chat_file 悬挂链接、27 条孤立 file 行、14 个物理上传文件共 9.88 MB。

环境排查

  • 确认 Open WebUI 版本:Issue 在 v0.11.3 与 dev 分支 commit 420b4a2797fa283cd15b5ee267380743115eca5f 上复现。
  • 确认安装方式:Docker。
  • 确认操作系统:Debian 13(Docker 容器)/ Linux x86_64。
  • 确认数据库类型:SQLite(默认 Docker 部署)为报告中的主要复现环境;PostgreSQL 情况见原因分析第 2 条。
  • 确认文件存储路径是否存在残留上传文件,例如 /app/backend/data/uploads/。
  • 确认数据库中是否存在悬挂关联,可执行 Issue 提供的审计查询:
SELECT cf.id, cf.chat_id, cf.file_id
FROM chat_file cf
LEFT JOIN chat c ON c.id = cf.chat_id
WHERE c.id IS NULL;

解决步骤

  1. 先确认当前是否存在泄漏数据。执行上面的审计查询,统计悬挂的 chat_file 行;再对 file 表检查是否存在未被 chat_file、knowledge_file、channel_file 任一引用的孤立记录。
  2. 备份数据库文件与 uploads/ 目录,避免清理过程中误删仍被引用的数据。
  3. 对照 backend/open_webui/models/chats.py 中 delete_chat_by_id(约第 2477 行)、delete_chat_by_id_and_user_id(约第 2489 行)、delete_chats_by_user_id(约第 2501 行)、delete_chats_by_user_id_and_folder_id(约第 2522 行)的删除逻辑,确认这些路径是否只删除了 chat 行而未处理 chat_file 与 file。
  4. 如需缓解,可优先尝试:对确认无其他所有者的孤立 file 行执行删除,并同步删除其磁盘文件与向量集合 file-{id},使数据库、磁盘与向量库三者一致。此项为基于 Issue 描述的推断处理,Issue 中未给出经验证的一键脚本。
  5. 关注官方对该 Issue 的修复进展,在修复版本中按正常流程删除聊天,观察是否还会残留 chat_file 行与上传文件。

验证方法

重新创建一个带附件的聊天并永久删除后,执行以下检查应全部满足:SELECT * FROM chat_file WHERE chat_id = '<chat_id>' 返回 0 行;SELECT * FROM file WHERE id = '<file_id>' 返回 0 行(前提是该 file 不再被任何 chat_file、knowledge_file、channel_file 引用);/app/backend/data/uploads/ 中对应的物理文件已被移除;向量库中 file-{id} 集合不再存在。

参考来源

open-webui/open-webui #31455

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 25901

发表回复

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