
.then is not called if previous event has cancels events
快速结论:在 Gradio Blocks 中使用 Textbox 的 stop_btn 时,如果 .stop() 事件包含 cancels 参数且后续链式调用 .then(),则 .then() 中的回调函数不会被触发。优先检查是否在 .stop() 中同时指定了 cancels 和 fn 或 .then(),可尝试将 .stop() 拆分为两次独立调用。
问题场景
用户在 Gradio 5.13.1(Windows)中使用 gr.Textbox(stop_btn=True) 为聊天机器人添加停止按钮,希望通过 msg.stop() 取消正在进行的流式输出事件,并在取消后执行一个清理函数(如 stop_func)。当在 msg.stop(cancels=[submit_event]) 后链式调用 .then(fn=stop_func) 时,stop_func 不会被调用。
报错原文
# 运行时无显式报错,但 stop_func 的 print 语句未输出
# 预期行为:按下停止按钮后,控制台应打印 "stop func called"
# 实际行为:控制台无任何输出,函数未执行
原因分析
根据 Issue 讨论,这是 Gradio 框架内部的事件调度问题。当一个 .stop() 事件同时包含 cancels 参数和后续 .then() 回调时,框架可能将取消动作与回调绑定在同一事件生命周期中,导致回调被意外跳过。可能原因包括:事件取消后后续链式事件未正确注册,或 cancels 参数的处理逻辑覆盖了 .then() 的依赖关系。
环境排查
- Gradio 版本:确认是否为 5.13.1 或更新版本(5.x 系列)
- 运行环境:Windows / Linux / macOS(Issue 中为 Windows)
- 依赖检查:确保 Gradio 已正确安装,且无其他插件干扰事件系统
解决步骤
- (可优先尝试) 将
.stop()事件拆分为两次独立调用:msg.stop( fn=None, cancels=[submit_event] ) msg.stop( fn=stop_func, inputs=None, outputs=None )即第一次
.stop()仅负责取消事件(不指定fn和.then()),第二次.stop()纯粹执行回调函数。这是 Issue 评论中验证有效的临时解决方案。 - 如果拆分后仍不生效,请检查
submit_event变量是否确实指向msg.submit(...).then(bot, chatbot, chatbot)的返回值(应为事件链的末端)。 - 确保
bot函数是生成器函数(yield),因为cancels取消生成器事件本身是正常用例。 - 如果问题依旧,可考虑在
stop_func中手动调用print或gr.Info()排除函数执行问题。
验证方法
运行修复后的代码,点击 Textbox 右侧的停止按钮(通常在输入框右侧),观察控制台是否打印 “stop func called”。同时确认聊天机器人的流式输出确实被取消(即输出中断)。如果回调函数执行且取消生效,则问题解决。


