Webhook file upload fails in async workflow because ToolFile owner differs from Trigger EndUser

该报错通常出现在使用 Webhook Trigger 上传文件、并异步执行工作流的场景中:Webhook 上传的 ToolFile 记录归属于 Webhook 创建者账号(Account ID),而异步执行时按 Trigger EndUser ID 做文件归属过滤,导致下游节点读取不到该文件。优先排

快速结论:该报错通常出现在使用 Webhook Trigger 上传文件、并异步执行工作流的场景中:Webhook 上传的 ToolFile 记录归属于 Webhook 创建者账号(Account ID),而异步执行时按 Trigger EndUser ID 做文件归属过滤,导致下游节点读取不到该文件。优先排查 Webhook 上传文件与执行用户之间的归属不一致问题。

适用环境:Dify 1.17.1;Self Hosted(Docker);工作流使用 Webhook Trigger,并包含单个文件参数(multipart/form-data),异步执行。

最快修复方案:暂无确认的一步修复方案。Issue 中报告者通过本地修改,将 ToolFile.user_id 设为 Trigger EndUser ID 后,同一工作流可以完成;这属于本地验证,未合入上游,不能视为正式修复。

注意事项:直接修改文件归属逻辑会影响文件访问控制模型;Issue 中建议的正式修复方向是:在 _create_file_from_binary() 中提前解析或创建 Trigger EndUser,或参照 PR #41300 的执行内授权机制(grant_tool_file_access)显式授权该文件 ID。两者均需回归测试,未验证前不要在生产环境直接套用。

问题场景

在 Dify 1.17.1(Self Hosted / Docker)中创建一个含 Webhook Trigger 的工作流:触发器接收一个字符串字段和一个文件字段(示例为 chat_history_file),通过 multipart/form-data 上传。文件字段连接到 Document Extractor 或邮件附件等下游节点,并以异步方式执行工作流。Webhook 端点返回 HTTP 200,但异步工作流失败。

报错原文

ToolFile <id> not found
Failed to build FileVariable for webhook file parameter chat_history_file
Variable ['<node-id>', 'chat_history_file'] is not an ArrayFileSegment

原因分析

根据 Issue 及维护者回复的分析,根因是文件归属与执行用户不一致:

  • WebhookService._create_file_from_binary() 创建 ToolFile 时使用 user_id=webhook_trigger.created_by,即工作流/Webhook 所有者的 Account ID。
  • trigger_workflow_execution() 执行工作流时使用通过 get_or_create_end_user_by_type(type=EndUserType.TRIGGER, ..., user_id=None) 得到的独立 Trigger EndUser,该 EndUser 的 ID 成为 WorkflowTriggerLog.created_by。
  • 异步任务按该 ID 重建执行用户,BaseAppGenerator._bind_file_access_scope() 为其绑定 FileAccessScope,并开启 requires_user_ownership = True。
  • DatabaseFileAccessController.apply_tool_file_filters() 在此作用域下只允许查找 ToolFile.user_id == scope.user_id 的记录(或位于本次执行 granted_tool_file_ids 白名单中的文件)。Webhook 上传的文件携带的是 Account ID,也不在授权集合中,因此抛出 ToolFile <id> not found,并导致后续节点变量段类型不匹配。

PR #41300 曾为“工作流作为工具”场景中工具产出的文件添加执行内授权(grant_tool_file_access),但 Webhook 上传发生在同步请求阶段,早于执行,未触发该授权机制,因此不覆盖此场景。这是基于 Issue 讨论的原因判断。

环境排查

  • 确认 Dify 版本是否为 1.17.1 或相近版本,并记录升级前后是否仍复现。
  • 确认部署形态:Self Hosted(Docker),排查 worker(Celery 异步任务)日志,检索 ToolFile、Failed to build FileVariable 等关键字。
  • 确认 Webhook Trigger 配置:文件参数是否为单文件字段、请求是否为 multipart/form-data。
  • 确认工作流是否以异步方式触发,并检查 WorkflowTriggerLog.created_by 对应的 EndUser 类型是否为 TRIGGER。
  • 检查该 ToolFile 记录的 user_id,确认其对应 Account ID 而非 Trigger EndUser ID。
  • 如同时遇到“缺少文件参数时回退到整个 files 映射”的现象,注意 Issue 提到的另一个问题 #41071,可能与本次测试相互干扰。

解决步骤

  1. 先复现并定位:用 curl 向 Webhook 发送带文件字段的 multipart/form-data 请求,确认返回 HTTP 200,同时检查 worker 日志中是否出现上述两条文件相关报错。
  2. 在数据库中核对该 ToolFile 的 user_id 与 WorkflowTriggerLog.created_by 是否指向不同用户(Account ID 与 Trigger EndUser ID)。
  3. 如需本地验证,可优先尝试:在 _create_file_from_binary() 中改用本次执行对应的 Trigger EndUser ID 创建 ToolFile;报告者以此方式验证同一工作流可成功完成。该方式仅为本地测试结论,非上游修复。
  4. 如采用代码侧修复,按 Issue 建议方向二选一:在创建 ToolFile 之前解析或创建 Trigger EndUser;或参照 PR #41300 的模式,将上传文件 ID 显式加入执行作用域的授权集合。
  5. 在修改后的环境中重新发送同样的 curl 请求,观察异步执行是否完整走完。

验证方法

重新触发一次相同的 Webhook 上传请求,确认:Webhook 返回 HTTP 200;worker 日志中不再出现 ToolFile <id> not found 与 Failed to build FileVariable for webhook file parameter chat_history_file;下游节点能正常获取文件,且不再报 Variable ['<node-id>', 'chat_history_file'] is not an ArrayFileSegment;异步工作流执行状态为成功。

参考来源

langgenius/dify #42987

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 33814

发表回复

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