Search code examples
pythondiscorddiscord.py

Why does my discord bot say it did not respond after it did?


I've been testing out the basics of writing a discord bot for a little project I'm working on, and I noticed that while the bot responds as intended when given a slash command, the sent command its self says that the application failed to respond. If anyone can point out where I'm being stupid, that would be much appreciated!

Here are some images of the problem

I send the command... it works... but the application didn't respond apparently?

Here's the test slash command that I'm using

@tree.command(name = "test", description = "test", guild=discord.Object(id=(idnu))
async def lal(ctx, last: str):
        response = "strresponse"
        await ctx.channel.send(response)

I also looked at a couple posts which are similar, I.E Discord bot "The application did not respond" yet the command send? but none seemed to answer my question, as I'm already responding last?

Thank you!


Solution

  • You are using discord.app_commands, not discord.ext.commands.

    When definig a command using app_commands, the first command parameter is not from type commands.Context, its discord.Interaction.

    Both objects (ctx and interaction) has a channel object as property so the message is being sent. However, this is not the way you are suppose to handle an interaction.

    All app_commands must have a response, that can be sent using the response object property from the interaction object.

    This is how your command should look like:

    from discord import app_commands, Interaction
    
    @bot.tree.command(name='test', description='command description')
    @app_commands.describe(last = '"last" parameter description') # Optional line
    async def test(interaction : Interaction, last : str):
        response = "str_response"
        await interaction.response.send_message(response)
    

    My previous sentence:

    "All app_commands must have a response, that can be sent using the response attribute from the interaction object"

    doesn't mean that you can't send "standard message" (channel.send()) as part of the command, but that you have to response to the interaction at least once.

    Interaction responses are the type of messages that look like this:

    Interaction response example

    If you want your command to only include "standard messages", you can set to True the ephemeral parameter when responding to the interaction with the send_message() coroutine from the response object.

    Making the response ephemeral makes the interaction response only visible for the user that executed the command, and it can be deleted at any time clicking on "Delete this message" (or "Eliminar este mensaje" in the next picture, sorry, I have Discord in Spanish):

    @bot.tree.command(name='test', description='command description')
    @app_commands.describe(last = '"last" parameter description')
    async def test(interaction : Interaction, last : str):
        response = "str_response"
        await interaction.channel.send(response)
        await interaction.response.send_message(content='Message Sent!', ephemeral=True)
    

    Second example

    Finally, if you want your command to include more than one interaction response, or you are expecting the command execution to not be brief (slow code, etc.) you have to defer the response, and then send the responses using interaction.followup.send() instead of interaction.response.send_message():

    @bot.tree.command(name='test', description='command description')
    @app_commands.describe(last = '"last" parameter description')
    async def test(interaction : Interaction, last : str):
        await interaction.response.defer()
        await interaction.followup.send('str_response')
        await interaction.followup.send('Another response!')
    

    Third example

    Now you are ready to join the app_commands commands side! 👀