使用asyncio运行discord.py机器人时不显示运行时错误
解决discord.py 2.1.0中cog运行时错误不显示的问题
你的问题核心是discord.py默认会捕获命令执行中的未处理异常且未主动输出到终端,和用asyncio.run()启动的方式无关。结合定时任务场景,以下是具体解决方案和最佳实践:
1. 全局命令错误捕获
在自定义Bot类中重写on_command_error方法,统一处理所有命令的异常,确保错误信息输出到终端:
import os import discord from discord.ext import commands import asyncio import traceback token = os.environ["BOT_TOKEN"] class Bot(commands.Bot): def __init__(self): intents = discord.Intents.default() intents.members = True intents.message_content = True description = "bot example." super().__init__( command_prefix=commands.when_mentioned_or('!'), intents=intents, description=description, debug=True # 开发阶段开启,输出更多调试细节 ) async def on_ready(self): print(f'Logged in as {self.user} (ID: {self.user.id})') print('------') async def on_command_error(self, ctx, error): # 忽略命令不存在的无效请求 if isinstance(error, commands.CommandNotFound): return # 打印完整异常栈到终端 traceback.print_exception(type(error), error, error.__traceback__) # 可选:给用户发送错误提示 await ctx.send("命令执行失败,请稍后重试。") bot = Bot() async def load_extensions(): for f in os.listdir("./cogs"): if f.endswith(".py"): await bot.load_extension("cogs." + f[:-3]) async def main(): async with bot: await load_extensions() await bot.start(token) asyncio.run(main())
2. 单个命令的针对性异常处理
如果只需要对特定命令做异常处理,直接在命令函数中添加try-except:
from discord.ext import commands import traceback class Test(commands.Cog): def __init__(self, client): self.client = client @commands.Cog.listener() async def on_ready(self): print("Ready") @commands.command() async def command(self, ctx): try: test_error_message() # 模拟运行时错误 print("Command") except Exception as e: traceback.print_exc() # 打印错误到终端 await ctx.send(f"执行出错:{str(e)}") # 告知用户错误信息 async def setup(client): await client.add_cog(Test(client))
3. 定时任务的异常处理
对于tasks.loop装饰的定时任务,有两种处理方式:
方式一:给定时任务单独加异常捕获
from discord.ext import tasks import traceback @tasks.loop(seconds=10) async def avatar_update(): try: # 你的定时任务逻辑 print("执行头像更新") # 模拟错误 raise ValueError("测试定时任务异常") except Exception as e: traceback.print_exc() # 可选:发送错误通知到指定管理频道 channel = bot.get_channel(123456789) # 替换为实际频道ID if channel: await channel.send(f"定时任务出错:{str(e)}")
方式二:全局异步异常处理器兜底
在main函数中设置事件循环的异常处理器,捕获所有未处理的异步任务异常:
def global_exception_handler(loop, context): """全局异步任务异常处理""" exception = context.get("exception") if exception: print("全局异步任务出错:") traceback.print_exception(type(exception), exception, exception.__traceback__) else: print(f"异步任务错误信息:{context['message']}") async def main(): loop = asyncio.get_running_loop() loop.set_exception_handler(global_exception_handler) async with bot: avatar_update.start() await load_extensions() await bot.start(token)
最佳实践总结
- 开发阶段开启Bot的
debug=True参数,获取更详细的调试日志 - 必须配置全局
on_command_error,覆盖所有命令的异常捕获 - 定时任务优先单独加
try-except,方便针对性处理;全局异步异常处理器作为兜底 - 异常信息要同时输出到终端(方便开发调试)和Discord频道(方便管理员知晓)
内容的提问来源于stack exchange,提问作者Allen Shen
相关产品推荐
相关产品推荐

