Search code examples
discorddiscord.py

Discord.py exception "Missing 1 required positional argument: 'ctx' " although I included 'ctx' as one of the function parameters


so I'm having an issue while creating a discord music bot and I've been trying to solve it for a while now, but I can't find any solution.

Here's the constructor and three functions to search and play music that are necessary for the command to actually work (I'll only include the skip command since I get the same exception with the rest of the commands)

class music(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

        self.is_playing = False
        self.is_paused = False

        self.music_queue = []
        self.YDL_OPTIONS = {"format": "bestaudio", "noplaylist": "True"}
        self.FFMPEG_OPTIONS = {"before_options": "-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5", "options": "-vn"}

        self.vc = None

        
    async def play_music(self, ctx):
        if len(self.music_queue) > 0:
            self.is_playing = True
            m_url = self.music_queue[0][0]["source"]

            if self.vc == None or not self.vc.is_connected():
                self.vc == await self.music_queue[0][1].connect()

                if self.vc == None:
                    await ctx.send("I'm sorry, but I can't join the voice channel")
                    return
            else:
                await self.vc.move_to(self.music_queue[0][1])
            
            self.music_queue.pop(0)

            self.vc.play(discord.FFmpegPCMAudio(m_url, **self.FFMPEG_OPTIONS), after=lambda e: self.play_next())

        else:
            self.is_playing = False

    
    def play_next(self):
        if len(self.music_queue) > 0:
            self.is_playing = True

            m_url = self.music_queue[0][0]["source"]

            self.music_queue.pop(0)

            self.vc.play(discord.FFmpegPCMAudio(m_url, **self.FFMPEG_OPTIONS), after=lambda e: self.play_next())
        else:
            self.is_playing = False


    def search(self, item):
        with YoutubeDL(self.YDL_OPTIONS) as ydl:
            try:
                info = ydl.extract_info("ytsearch:{0}".format(item), download=False)["entries"][0]
            except Exception:
                return False
        return {"source": info["formats"][0]["url"], "title": info["title"]}

async def setup(client):
    await client.add_cog(music(client))

bot.py with setup_hook and the command

class MyBot(commands.Bot):
    async def setup_hook(self):
        await self.load_extension("dustobot")

@commands.command(aliases=["s"], help="Skips the current song that is being played")
    async def skip(self, ctx, *args):
        if self.vc != None and self.vc:
            self.vc.stop()
            await self.play_music(ctx) #Calling a function that plays the next song in a queue

And this is the error I get:

2023-01-21 12:28:37 ERROR    discord.ext.commands.bot Ignoring exception in command skip
Traceback (most recent call last):
  File "C:\Users\private_path\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 229, in wrapped
    ret = await coro(*args, **kwargs)
TypeError: music.skip() missing 1 required positional argument: 'ctx'

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

Traceback (most recent call last):
  File "C:\Users\private_path\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\bot.py", line 1349, in invoke 
    await ctx.command.invoke(ctx)
  File "C:\Users\private_path\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 1023, in invoke
    await injected(*ctx.args, **ctx.kwargs)  # type: ignore
  File "C:\Users\private_path\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\discord\ext\commands\core.py", line 238, in wrapped       
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: music.skip() missing 1 required positional argument: 'ctx'

Is it because I'm using a deprecated discord.py syntax?

Thanks in advance for taking your time to help me, I really appreciate it.

Btw this is my main.py:

import os
import discord
from dustobot import music #This imports the music class
from dotenv import load_dotenv
from discord.ext import commands

load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')

intents = discord.Intents.default()
intents.message_content = True

client = commands.Bot(command_prefix="!", intents=intents)

client.remove_command("help") #I have my own help command


if __name__ == "__main__":
    client.run(TOKEN)

Solution

  • The issue is caused by the way you created the command:

        #client refers to the bot
        @client.command(aliases=["s"], help="Skips the current song that is being played")
    

    The decorator doesn't expect this to be a method in a class. As such, it's not invoked as a method either, so self won't be passed automatically and the Context will be the first argument (self). As a result, the library won't pass a value for ctx, which results in your error.

    In cogs, commands should be created using @commands.command instead of @<Bot_instance>.command, the reason being that you shouldn't have your Bot instance available to you in that scope.

    You could've also gotten this by reading the manual for Cogs...

    Every command is marked with the commands.command() decorator.