Errors and replies
success() and error()
Most commands end by telling someone it worked or it didn't. Ruby has two helpers so every command does it the same way:
from ruby.utils import error, success
await success(ctx) # ✅
await success(ctx, "Saved your birthday!") # ✅ + a green embed
await error(ctx) # ❌
await error(ctx, "That isn't a real date.") # ❌ + a red embedHow they look depends on how the command was used:
Prefix command (r!wave) | Slash command (/wave) | |
|---|---|---|
| No message | Reacts ✅ / ❌ to the command | Replies "✅" / "❌" |
| With a message | Reacts and replies with the message | Replies with the message |
No message, silent_on_slash=True | Reacts ✅ / ❌ | Says nothing (no "The application did not respond") |
Messages are coloured embeds by default. Set embeds: false in the config for plain ✅ | message text instead.
Small things they handle for you:
- If the reaction can't be added (message deleted, no permission, the bot is blocked), they reply instead, so the result isn't lost.
- If the command message has been deleted, the reply is still sent, just without the "replying to" link.
- The message can be a string key or plain text.
silent_on_slash
Use it when the command sends its own output and the ✅ is only a receipt for prefix users:
await success(ctx, silent_on_slash=True) # ✅ on r!help, nothing extra on /help
await ctx.reply(embed=help_embed)When a command fails
You don't need try/except around every command. Ruby has an error handler for prefix, hybrid and plain slash commands. It replies to the user and logs what the bot owner needs to know:
| What went wrong | User sees | Logged |
|---|---|---|
| On cooldown | COMMAND_ON_COOLDOWN, with a "try again in…" timestamp | |
commands.is_owner() failed | NOT_OWNER | warning: who tried, and where |
| No such command | COMMAND_NOT_FOUND | warning |
| User is missing permissions | COMMAND_MISSING_PERMISSION(S) | |
| Bot is missing permissions | COMMAND_BOT_MISSING_PERMISSION(S) | |
| Missing argument | e.g. "Member is a required argument that is missing." | |
| Bad argument, failed check, disabled command, max concurrency | discord.py's message, e.g. "Member "bob" not found." | |
| An exception in your code | UNKNOWN_ERROR | error, with the exception |
| Anything else | UNKNOWN_COMMAND_ERROR | error |
The user always gets a short message, and the details go to the log, not the chat.
Custom checks
Raise commands.CheckFailure("message") from a check, and that message is what the user sees.
Stopping a command early
The usual way is to reply and return:
if await require_guild(ctx):
returnDeep inside helper functions, where returning would mean passing a flag back up through every caller, you can raise ZeroDivisionError instead. Ruby treats it as "stop here, quietly": no error reply and nothing logged. Reply to the user before raising it.
async def charge(ctx: Context, amount: int) -> None:
if balance < amount:
await error(ctx, "You can't afford that.")
raise ZeroDivisionError # ends the command, nothing else happensWARNING
Only use this deliberately. A real ZeroDivisionError (an actual x / 0 bug) is hidden in the same way. It won't show up in the logs.