如何定位触发「Future exception was never retrieved」报错的Future对象
定位未捕获异常的Future对象的具体方法
方法1:注册全局事件循环异常钩子
- 在事件循环启动前添加自定义异常处理回调,直接捕获所有未处理的Future异常,同时输出Future的创建调用栈,示例代码如下:
import asyncio import traceback def uncaught_future_handler(loop, context): # 先输出默认的异常信息 loop.default_exception_handler(context) # 提取上下文里的Future对象 err_future = context.get('future') if err_future: print("\n*该Future对象的创建调用栈如下:*") # 打印Future创建时的完整调用栈 traceback.print_stack(err_future.get_stack()[0].f_back) # 给当前事件循环绑定处理函数 asyncio.get_event_loop().set_exception_handler(uncaught_future_handler)
- 运行添加了这段代码的程序,出现未捕获Future异常时就会直接打印该对象的创建位置,你可以直接定位到对应代码行。
方法2:开启Python异步调试模式
- 不需要修改代码,直接在启动脚本时添加环境变量
PYTHONASYNCIODEBUG=1即可,启动命令示例:PYTHONASYNCIODEBUG=1 python 你的脚本文件名.py - 注意:调试模式下asyncio会自动记录所有Future的创建栈,未捕获异常发生时会自动把创建栈和异常栈一起输出,定位完问题后记得关闭该模式,避免额外性能损耗。
方法3:针对当前Telethon报错的专项排查
- 你当前的报错属于Telethon的连接异常,该Future大概率是
client.connect()协程对应的包装对象,你可以全局搜索你代码中所有调用client.connect()的位置,检查以下两类问题:- 调用
client.connect()时漏写await,导致协程对象没有被执行,异常直接抛到事件循环 - 把
client.connect()包装成asyncio.Task后没有添加add_done_callback捕获异常,也没有后续await该Task的逻辑
- 调用
内容的提问来源于stack exchange,提问作者MMM
相关产品推荐
相关产品推荐

