I’m working on a Discord bot using Python and I want users to be able to add their own commands directly from the server chat. From my research, it looks like I need to use a dictionary to store these custom commands.
I found some code from an old forum post and modified it a bit:
When someone types !add dog woof, I want the bot to create a new command where:
Input: !dog
Output: woof
The bot recognizes the !add command and I can see the arguments in the console, but it doesn’t save them properly. When I try to use the newly created command, I get a “Command not found” error.
The bot is online and has message content intent enabled. Here’s what I see in the terminal:
2025-03-18 23:21:38 INFO discord.client logging in using static token
2025-03-18 23:21:39 INFO discord.gateway Shard ID None has connected to Gateway
Command triggered
[add_command] ctx: <discord.ext.commands.context.Context object at 0x000001B2BDA1F6E0>
[add_command] arguments: ()
Command triggered
[add_command] ctx: <discord.ext.commands.context.Context object at 0x000001B2BC4DBB30>
[add_command] arguments: ('dog', 'woof')
2025-03-18 23:22:01 ERROR discord.ext.commands.bot Ignoring exception in command None
discord.ext.commands.errors.CommandNotFound: Command "dog" is not found
everyone’s talking about the @client.event issue, but there’s another problem - your add_command function only saves the first word of multi-word responses. if someone types !add hello this is a test, your code just grabs “this” and ignores the rest. use response_text = ' '.join(arguments[1:]) instead of arguments[1] to capture the whole response.
You’re missing the @client.event decorator before your on_message function. But there’s a bigger issue - you’re calling process_commands after handling custom commands, which triggers the CommandNotFound error.
I hit this same problem building a bot last year. You need to return early when you find a custom command match so the bot doesn’t try processing it as a regular command. Also, get rid of that duplicate code block in your on_message function.
Here’s the fix:
@client.event
async def on_message(message):
if message.author.bot:
return
command, *arguments = message.content.split(' ')
if command in custom_commands:
reply = custom_commands[command]
await message.reply(reply)
return # Important: exit here
await client.process_commands(message)
This handles custom commands first, then only processes non-custom messages as regular bot commands.
Yeah, the missing @client.event decorator is your problem, but I’ve hit this same issue at work and there’s a way better solution.
Your setup has a major flaw - everything vanishes when the bot restarts. Users add commands, server goes down, and poof - all custom commands are gone. You’ll also get permission headaches and security issues when users create conflicting commands.
I built something like this for our internal tools and ditched the local dictionary completely. Used Latenode instead to create a proper workflow system. When users type !add dog woof, it hits a webhook that stores the command in a database and creates a dynamic response handler.
Latenode handles all the persistence, scaling, and API stuff automatically. Your Discord bot stays lightweight - just forwards requests and gets responses back. No more data loss, messy validation, or command conflicts.
You can add command analytics, usage limits, and admin overrides without touching your bot code. Way more maintainable.
Quick fix: add the @client.event decorator and remove duplicate code. But seriously look into automation platforms for anything beyond basic testing.
you’re missing the @client.event decorator on your on_message func. without it, discord.py won’t call your handler and your custom commands won’t work. also, you’ve got duplicate code in on_message - looks like a copy-paste mistake. just remove one of them.
Your on_message function has a logic problem. You’re checking for custom commands but then always calling process_commands, which tries to find a built-in command that doesn’t exist.
You’re also missing @client.event above the on_message function.
But honestly, dynamic commands get messy fast. Commands vanish when the bot restarts, permissions become a nightmare, and scaling sucks.
I’ve handled similar stuff at work and found Latenode makes this way cleaner. Set up workflows that handle Discord webhooks and store custom commands in a database. When users add commands, Latenode automatically creates the API endpoints and manages data persistence.
Best part? No worrying about bot restarts killing your data or building complex permission systems. Latenode handles the heavy lifting while you focus on Discord integration.
Quick fix for your current code: add @client.event before on_message and remove the duplicate command checking. But seriously consider automation platforms for production.
Your on_message function isn’t working because you’re missing the @client.event decorator. Without it, discord.py never calls your function when messages come in. Plus, you’ve got duplicate code blocks causing conflicts.
I hit this same problem building a custom command system for my guild’s bot. Here’s what’s happening - when you call process_commands after matching a custom command, it still tries to parse the message as a built-in command. That’s why you’re getting CommandNotFound errors.
Besides fixing the decorator, add some basic validation so users can’t override existing bot commands. I learned this the hard way when someone accidentally overwrote our help command. Just check against client.all_commands before storing new commands - it’ll save you tons of headaches.
You’re right about the missing @client.event decorator - that’s your main problem. But there’s another issue that’ll bite you later. Your add_command function gives users zero feedback when they create a command. I built something similar and users kept spamming the same command because they had no clue if it worked. Throw in a quick confirmation like await ctx.send(f'Command {command_name} added successfully!') at the end. Also check if the command exists before overwriting it. And seriously, add a way to list/remove custom commands now - you’ll definitely need it once people start hammering this feature.