Обработка ошибок discord py

I want my bot to send a message to the chat when someone types a non-existent command. I tried this but nothing happened. Here is the code:

import discord
from discord.ext import commands

bot = commands.Bot(command_prefix=BOT_PREFIX)

@bot.event
async def on_ready():
    print("Logged in as: " + bot.user.name + "\n")

@bot.command()
async def asdasd(ctx):
    try:
        if asdasd:
            await ctx.send('asd')
    except discord.ext.commands.errors.CommandNotFound:
        await ctx.send('error')

bot.run('My Token Here')

Diggy.'s user avatar

Diggy.

6,7543 gold badges19 silver badges38 bronze badges

asked May 13, 2020 at 21:06

musta21's user avatar

There’s an exception handler event specifically for this!

Example:

@bot.event
async def on_command_error(ctx, error):
    if isinstance(error, discord.ext.commands.errors.CommandNotFound):
        await ctx.send("That command wasn't found! Sorry :(")

Read up more about it here. All the different errors can be found here.

Good luck!

Community's user avatar

answered May 13, 2020 at 21:25

Diggy.'s user avatar

Diggy.Diggy.

6,7543 gold badges19 silver badges38 bronze badges

1

При запуске неизвестной команды бот пишет в запущенную консоль:
Ignoring exception in command None:
discord.ext.commands.errors.CommandNotFound: Command «habr» is not found

Я уже сделал обработку ошибок с командой kick, но там охватывается только одна команда.
Как сделать вывод ошибки .CommandNotFound — не ясно.

p.s. я нашёл ответ. публикую, кому надо
# Команда не найдена
@client.event
async def on_command_error(ctx, error):
if isinstance(error, commands.CommandNotFound):
await ctx.send(embed = discord.Embed(description = f'{ctx.author.name}, команда не найдена!’, colour = discord.Color.red()))


  • Вопрос задан

  • 7397 просмотров

Пригласить эксперта

Если ещё не поздно вот

@client.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.CommandNotFound ):
        await ctx.send(embed = discord.Embed(description = f'** {ctx.author.name}, данной команды не существует.**', color=0x0c0c0c))

Что такое ‘discord.ext.commands.errors.CommandNotFound’ — это исключение?(Я с Discord не работал)
Если да, тогда наверное так:

try:
	тут код обработки команд
except discord.ext.commands.errors.CommandNotFound:
	# Здесь код выполнится только при ошибке CommandNotFound

Знаю что поздно, но вдруг кому-то пригодиться.
У меня так:

@client.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.CommandNotFound):
        title_error_two = 'Введенная вами команда не существует'
        desc_error_two = 'Используйте **!help**, чтобы просмотреть список всех доступных команд'
        embed_var_two = discord.Embed(title=title_error_two,
                                      description=desc_error_two,
                                      color=0xFF0000)
        await ctx.reply(embed=embed_var_two)


  • Показать ещё
    Загружается…

22 сент. 2023, в 07:45

40000 руб./за проект

22 сент. 2023, в 07:00

5000 руб./за проект

22 сент. 2023, в 06:12

25000 руб./за проект

Минуточку внимания

If you’re not recieving any errors in your console, even though you know you should be, try this:

With bot subclass:¶

import discord
from discord.ext import commands

import traceback
import sys

class MyBot(commands.Bot):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    async def on_command_error(self, ctx: commands.Context, error):
        # Handle your errors here
        if isinstance(error, commands.MemberNotFound):
            await ctx.send("I could not find member '{error.argument}'. Please try again")

        elif isinstance(error, commands.MissingRequiredArgument):
            await ctx.send(f"'{error.param.name}' is a required argument.")
        else:
            # All unhandled errors will print their original traceback
            print(f'Ignoring exception in command {ctx.command}:', file=sys.stderr)
            traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)

bot = MyBot(command_prefix="!", intents=discord.Intents.default())

bot.run("token")

Without bot subclass¶

import discord
from discord.ext import commands

import traceback
import sys

async def on_command_error(self, ctx: commands.Context, error):
    # Handle your errors here
    if isinstance(error, commands.MemberNotFound):
        await ctx.send("I could not find member '{error.argument}'. Please try again")

    elif isinstance(error, commands.MissingRequiredArgument):
        await ctx.send(f"'{error.param.name}' is a required argument.")
    else:
        # All unhandled errors will print their original traceback
        print(f'Ignoring exception in command {ctx.command}:', file=sys.stderr)
        traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)

bot = commands.Bot(command_prefix="!", intents=discord.Intents.default())
bot.on_command_error = on_command_error

bot.run("token")

Make sure to import traceback and sys!


Useful Links:
— FAQ
— Simple Error Handling

There are many reasons why you can get an error, ranging from Discord API errors raised by the discord.py library to simple coding mistakes.

Example command with error⚓︎

Let’s take the command foo, which gets some error. We will simply divide by zero within in the example, although there may be any error.

Python

@bot.command()
async def foo(ctx: commands.Context):
    1 / 0

When we run the command, we will encounter the following error:

Python

Traceback (most recent call last):
  File "...\lib\site-packages\discord\ext\commands\core.py", line 235, in wrapped
    ret = await coro(*args, **kwargs)
  File "main.py", line ..., in foo
    1 / 0
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "...\lib\site-packages\discord\ext\commands\bot.py", line 1350, in invoke
    await ctx.command.invoke(ctx)
  File "...\lib\site-packages\discord\ext\commands\core.py", line 1029, in invoke
    await injected(*ctx.args, **ctx.kwargs)  # type: ignore
  File "...\lib\site-packages\discord\ext\commands\core.py", line 244, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: ZeroDivisionError: division by zero

Usually, we don’t want that, right? We wish to respond to the error in some way, like informing the user.

So let’s handle the error!

Basic error handling (try-except)⚓︎

In Python, try-except is typically used to capture exceptions. Of course, you can also use them in discord.py, but doing so is less comfortable and has some drawbacks (not everything in discord.py can be captured with it).

Python

@bot.command()
async def foo(ctx: commands.Context):
    try:
        1 / 0
    except ZeroDivisionError:
        await ctx.send("Error: division by zero attempt")

Showcase

Note

With such code, you cannot handle exceptions from things like checks or cooldowns and errors which occur in the command itself, but not in the try-except block.

What library does with the errors⚓︎

When a command in Discord.py encounters an error, the library handles it in the following order rather than terminating the code with an error:

  • Run the command’s error handler if it has one.
  • Run the cog error handler if command is contained within a cog and the cog has one.
  • Run the global command error handler if exists.
  • Print the error in the stderr without quitting the program if there are no error handlers.
graph LR
    A[Command] -->|exists?| B[Command Error Handler]
    A --> C[Cog]
    C -->|exists?| D[Cog Error Handler]
    C --> E[Global]
    E -->|exists?| F[Global Command Error Handler]
    E -. no handlers? .-> G[Print error in stderr]

Warning

Making an error handler will suppress any errors, making it difficult to debug your code. Normally, if your handler doesn’t pass any conditions, you print out the error (or do something similar).

Exception Hierarchy⚓︎

The discord.py documentation contains a list of all errors and their hierarchy.

Command Handler⚓︎

To create a handler for a single command, use Command.error decorator. This handler will only operate with this command, not any others.

Python

@bot.command()
async def foo(ctx: commands.Context):
    1 / 0

@foo.error
async def foo_error(ctx: commands.Context, error: commands.CommandError):
    await ctx.send(error)

Showcase

Much better! But to a user who is not a programmer, it does not appear to be very understandable So we can simply format it whatever we like. Built-in isinstance function is suggested as a method for determining the type of error.

Python

@foo.error
async def foo_error(ctx: commands.Context, error: commands.CommandError):
    embed = discord.Embed(title="Error")
    if isinstance(error, commands.CommandInvokeError):
        error = error.original
    if isinstance(error, ZeroDivisionError):
        embed.description = "Division by zero attempt"
    else:
        embed.description = "Unknown error"
    await ctx.send(embed=embed)

Showcase

Note

If there is an actual error in your code, then it will be a CommandInvokeError. We can use its original or __cause__ attribute to retrieve the original error.

Python

error = error.__cause__

Cog Handler⚓︎

You can set up a cog handler if there are several commands with the same exceptions in the same cog.

For that you need create a cog and override Cog.cog_command_error method.

Python

import traceback

import discord
from discord.ext import commands

class Example(commands.Cog):
    @commands.command()
    async def foo(self, ctx: commands.Context):
        1 / 0

    async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError):
        embed = discord.Embed(title="Error")
        if isinstance(error, commands.CommandInvokeError):
            error = error.original
        if isinstance(error, ZeroDivisionError):
            embed.description = "Division by zero attempt"
        else:
            error_data = "".join(traceback.format_exception(type(error), error, error.__traceback__))
            embed.description = f"Unknown error\n```py\n{error_data[:1000]}\n```"
        await ctx.send(embed=embed)


async def setup(bot: commands.Bot):
    await bot.add_cog(Example())

Showcase

Warning

Make sure to load your cogs otherwise commands will not be registered to bot and there will be no response. To load cogs, use the Bot.load_extension method.

Python

await bot.load_extension("cogs.example")

Global Handler⚓︎

It can get very boring to handle errors for each command or cog separately. Especially when we do it similarly everywhere.

Let’s make a global error handler, that will be used by all commands.

For that you need to override bot’s on_command_error method.

In order to accomplish this, you can either subclass the bot and modify its method, or use Bot.event or Bot.listen decorator.

Python

import traceback

import discord
from discord.ext import commands

@bot.command()
async def foo(ctx: commands.Context):
    1 / 0

@bot.event
async def on_command_error(ctx: commands.Context, error: commands.CommandError):
    embed = discord.Embed(title="Error")
    if isinstance(error, commands.CommandInvokeError):
        error = error.original
    if isinstance(error, ZeroDivisionError):
        embed.description = "Division by zero attempt"
    else:
        error_data = "".join(traceback.format_exception(type(error), error, error.__traceback__))
        embed.description = f"Unknown error\n```py\n{error_data[:1000]}\n```"
    await ctx.send(embed=embed)

Showcase

Warning

Always make sure to have an else clause in your error handler. Otherwise, you will not be able to see the actual error if it is not one of the expected ones.

Python

@bot.event
async def on_command_error(ctx: commands.Context, error: commands.CommandError):
    embed = discord.Embed(title="Error")
    if isinstance(error, commands.CommandInvokeError):
        error = error.original
    if isinstance(error, ZeroDivisionError):
        embed.description = "Division by zero attempt"
    # else:
    #     embed.description = "Unknown error"
    await ctx.send(embed=embed)

In such a situation, you will not be able to see the actual error as the error handler will be eating away the error.

Expanded Example⚓︎

Sequential handling⚓︎

Both will be executed if command has an error handler and command’s cog has an error handler. We can use it to only check for errors where we have to.

Let’s use such command foo and consider that the first error might occur in any command, the second could occur only in that command cog, and the third could only occur in this command.

Python

class Example(commands.Cog):
    async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError):
        if isinstance(error, commands.CommandInvokeError) and isinstance(error.original, ValueError):
            await ctx.send("Got ValueError inside the cog handler")

    @commands.command()
    async def foo(self, ctx: commands.Context, arg: int):
        if arg == 1:
            1 / 0
        if arg == 2:
            int("x")
        if arg == 3:
            {"hello": "world"}["test"]

    @foo.error
    async def foo_error(self, ctx: commands.Context, error: commands.CommandError):
        if isinstance(error, commands.CommandInvokeError) and isinstance(error.original, KeyError):
            await ctx.send("Got KeyError inside the command handler")


@bot.event
async def setup_hook():
    await bot.add_cog(Example())


@bot.event
async def on_command_error(ctx: commands.Context, error: commands.CommandError):
    if isinstance(error, commands.CommandInvokeError) and isinstance(error.original, ZeroDivisionError):
        await ctx.send("Got ZeroDivisionError inside the global handler")

Showcase

Full bot with more errors⚓︎

An expanded example with some additional errors:

Python

import datetime
import traceback

import discord
from discord.ext import commands

intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(".", intents=intents)


class AuthorHasLowerRole(commands.CommandError):
    """Exception raised when user tries to move the user which has a better role"""


@bot.event
async def on_command_error(ctx: commands.Context, error: commands.CommandError):
    if isinstance(error, commands.CommandNotFound):
        return
    if not isinstance(error, commands.CommandOnCooldown):
        ctx.command.reset_cooldown(ctx)
    embed = discord.Embed(
        title=f"Error in command {ctx.command}!",
        description="Unknown error occurred while using the command",
        color=discord.Color.red(),
        timestamp=datetime.datetime.utcnow()
    )
    if isinstance(error, commands.CommandInvokeError):
        if isinstance(error.original, ZeroDivisionError):
            embed.description = "Can't divide by zero"
    elif isinstance(error, commands.CommandOnCooldown):
        embed.description = f"This command is on cooldown. You need to wait {error.retry_after:.2f} to use that command"
    elif isinstance(error, AuthorHasLowerRole):
        embed.description = "You can't manage this member because he has a better role than yours"
    elif isinstance(error, commands.BotMissingPermissions):
        embed.description = f"I am missing required permissions to do that"
        embed.add_field(name="List of permissions", value=', '.join(error.missing_permissions))
    elif isinstance(error, commands.MissingPermissions):
        embed.description = f"You are missing required permissions to do that"
        embed.add_field(name="List of permissions", value=', '.join(error.missing_permissions))
    elif isinstance(error, commands.BadArgument):
        if isinstance(error, commands.MemberNotFound):
            embed.description = f"Member `{error.argument}` not found"
        elif isinstance(error, commands.ChannelNotFound):
            embed.description = f"Channel `{error.argument}` not found"
    elif isinstance(error, commands.MissingRequiredArgument):
        embed.description = f"Missing required argument: `{error.param.name}`"
    else:
        error_data = "".join(traceback.format_exception(type(error), error, error.__traceback__))
        embed.description = f"Unknown error\n```py\n{error_data[:1000]}\n```"
    await ctx.send(embed=embed)


@bot.command()
async def divide(ctx: commands.Context, a: int, b: int):
    await ctx.send(f"{a} / {b} = {a / b}")


@bot.command()
@commands.cooldown(1, 10, commands.BucketType.user)
@commands.has_guild_permissions(move_members=True)
async def move(ctx: commands.Context, member: discord.Member, channel: discord.VoiceChannel, *, reason="No reason provided"):
    if ctx.author.top_role <= member.top_role:
        raise AuthorHasLowerRole()
    await member.move_to(channel, reason=reason)
    await ctx.reply("Moved!")

bot.run("TOKEN")

Note

When a command encounters any exception, it still updates the cooldown, so this code resets it:

Python

if not isinstance(error, commands.CommandOnCooldown):
    ctx.command.reset_cooldown(ctx)

Using it or not is entirely up to you.

Showcase

Showcase

  • If we use that command and the member is not connected to any voice, we receive an unknown error because we didn’t handle it (none of our conditions were met).

Showcase

  • However, this command will function properly if the user is connected to a voice channel.

Showcase

«»» If you are not using this inside a cog, add the event decorator e.g: @bot.event async def on_command_error(ctx, error) For examples of cogs see: https://gist.github.com/EvieePy/d78c061a4798ae81be9825468fe146be For a list of exceptions: https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#exceptions «»» import discord import traceback import sys from discord.ext import commands class CommandErrorHandler(commands.Cog): def __init__(self, bot): self.bot = bot @commands.Cog.listener() async def on_command_error(self, ctx, error): «»»The event triggered when an error is raised while invoking a command. Parameters ———— ctx: commands.Context The context used for command invocation. error: commands.CommandError The Exception raised. «»» # This prevents any commands with local handlers being handled here in on_command_error. if hasattr(ctx.command, ‘on_error’): return # This prevents any cogs with an overwritten cog_command_error being handled here. cog = ctx.cog if cog: if cog._get_overridden_method(cog.cog_command_error) is not None: return ignored = (commands.CommandNotFound, ) # Allows us to check for original exceptions raised and sent to CommandInvokeError. # If nothing is found. We keep the exception passed to on_command_error. error = getattr(error, ‘original’, error) # Anything in ignored will return and prevent anything happening. if isinstance(error, ignored): return if isinstance(error, commands.DisabledCommand): await ctx.send(f’{ctx.command} has been disabled.’) elif isinstance(error, commands.NoPrivateMessage): try: await ctx.author.send(f’{ctx.command} can not be used in Private Messages.’) except discord.HTTPException: pass # For this error example we check to see where it came from… elif isinstance(error, commands.BadArgument): if ctx.command.qualified_name == ‘tag list’: # Check if the command being invoked is ‘tag list’ await ctx.send(‘I could not find that member. Please try again.’) else: # All other Errors not returned come here. And we can just print the default TraceBack. print(‘Ignoring exception in command {}:’.format(ctx.command), file=sys.stderr) traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr) «»»Below is an example of a Local Error Handler for our command do_repeat»»» @commands.command(name=‘repeat’, aliases=[‘mimic’, ‘copy’]) async def do_repeat(self, ctx, *, inp: str): «»»A simple command which repeats your input! Parameters ———— inp: str The input you wish to repeat. «»» await ctx.send(inp) @do_repeat.error async def do_repeat_handler(self, ctx, error): «»»A local Error Handler for our command do_repeat. This will only listen for errors in do_repeat. The global on_command_error will still be invoked after. «»» # Check if our required argument inp is missing. if isinstance(error, commands.MissingRequiredArgument): if error.param.name == ‘inp’: await ctx.send(«You forgot to give me input to repeat!») def setup(bot): bot.add_cog(CommandErrorHandler(bot))

Понравилась статья? Поделить с друзьями:
  • Образец постановление о технической ошибке
  • Обработка ошибок curl php
  • Оборудование для считывания ошибок автомобиля
  • Образец претензии на врачебную ошибку
  • Обозначение ошибок на приборной панели газель бизнес