You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord等级系统报错:TypeError: on_message()缺少必填参数'ctx'

Fixing the TypeError: on_message() missing 1 required positional argument: 'ctx' in Your Discord.py Level System

Let's break down what's causing this error and fix your level system step by step:

1. The Core Issue: Incorrect Event Listener Setup

Your on_message method in the Levels cog is missing the required decorator and has an incorrect parameter signature. In Discord.py cogs, event listeners need to be marked with @commands.Cog.listener(), and the on_message event only takes self and message as parameters (no ctx here). Discord.py was throwing the error because it couldn't match the expected argument structure.

2. Broken Command Decorator

When defining commands inside a cog, you can't use @client.command() — you need to use @commands.command() instead. Cogs rely on the commands module's decorators to properly bind to the bot instance, so using the client-level decorator breaks the cog's functionality.

3. Other Minor Bugs to Fix

  • In your level command, you're checking if member.id exists in self.users, but your JSON stores IDs as strings. You need to convert member.id to a string for the check to work.
  • Your embed has two fields both named "Level" — change the second one to "EXP" or "Experience" to avoid confusion.
  • Added a safety check for missing users.json files to prevent startup crashes.
  • Reduced the save interval from 5 seconds to 5 minutes to avoid excessive disk writes (a more reasonable frequency for data persistence).

Corrected Full Code

import discord
import asyncio
import json
from discord.ext import commands

class Levels(commands.Cog):  # Inherit from commands.Cog for proper cog functionality
    def __init__(self, client):
        self.bot = client
        self.bot.loop.create_task(self.save_users())
        # Handle missing JSON file gracefully
        try:
            with open(r'C:\Users\conex_000\PycharmProjects\Shirochka\users.json', 'r') as f:
                self.users = json.load(f)
        except FileNotFoundError:
            self.users = {}

    async def save_users(self):
        await self.bot.wait_until_ready()
        while not self.bot.is_closed():
            with open(r'C:\Users\conex_000\PycharmProjects\Shirochka\users.json', 'w') as f:
                json.dump(self.users, f, indent=4)
            await asyncio.sleep(300)  # Save every 5 minutes instead of 5 seconds

    def lvl_up(self, author_id):
        cur_xp = self.users[author_id]['exp']
        cur_lvl = self.users[author_id]['level']
        required_xp = round((4 * (cur_lvl ** 3)) / 5)
        if cur_xp >= required_xp:
            self.users[author_id]['level'] += 1
            # Reset XP to the amount over the required threshold (optional but cleaner)
            self.users[author_id]['exp'] = cur_xp - required_xp
            return True
        else:
            return False

    @commands.Cog.listener()  # Mandatory decorator for cog event listeners
    async def on_message(self, message):
        if message.author == self.bot.user:
            return
        author_id = str(message.author.id)
        if author_id not in self.users:
            self.users[author_id] = {
                'level': 1,
                'exp': 0
            }
        self.users[author_id]['exp'] += 1
        if self.lvl_up(author_id):
            await message.channel.send(f"{message.author.mention} is now level {self.users[author_id]['level']}! 🎉")

    @commands.command(name="level")  # Use commands.command() for cog commands
    async def level_command(self, ctx, member: discord.Member = None):
        member = ctx.author if not member else member
        member_id = str(member.id)
        if member_id not in self.users:
            await ctx.send("This user hasn't sent any messages yet!")
        else:
            embed = discord.Embed(color=member.color, timestamp=ctx.message.created_at)
            embed.set_author(name=f'Level Info - {member.display_name}', icon_url=member.avatar.url)
            embed.add_field(name='Level', value=self.users[member_id]['level'], inline=True)
            embed.add_field(name='EXP', value=self.users[member_id]['exp'], inline=True)
            # Optional: Add progress to next level
            required_xp = round((4 * (self.users[member_id]['level'] ** 3)) / 5)
            embed.add_field(name='To Next Level', value=f"{self.users[member_id]['exp']}/{required_xp}", inline=False)
            await ctx.send(embed=embed)

# Don't forget to load the cog in your main bot code!
# Example:
# client = commands.Bot(command_prefix="!", intents=discord.Intents.all())
# client.add_cog(Levels(client))
# client.run("YOUR_BOT_TOKEN")

Key Improvements Added

  • Added error handling for missing users.json files to prevent startup crashes
  • Reduced save frequency to avoid unnecessary disk wear
  • Improved the level-up logic to reset XP after leveling up (cleaner progression)
  • Enhanced the embed to show the user's avatar and progress to the next level
  • Renamed the command method to avoid name conflicts with the class itself

After making these changes, restart your bot, send a few messages, and you should see the level-up messages work correctly. The !level command will also display the user's level and experience properly.

内容的提问来源于stack exchange,提问作者Clonexy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:56:22