Sage Mode
Automatic replies, deferrals, and error handling
Sage automatically handles how your bot responds to commands — sending replies, deferring slow commands, and formatting error messages during development.
For the Sage resolution chain, async-only deferral behavior, and context menu support, see the @robojs/discordjs Sage reference.
Automatic Replies
Return a value from your command handler instead of calling interaction.reply(). Sage detects the return value and sends it as the reply.
A string return sends a plain text reply.
export default () => {
return 'Pong!'
}export default () => {
return 'Pong!'
}An object return supports full InteractionReplyOptions, including ephemeral messages.
export default () => {
return { content: 'Pong!', ephemeral: true }
}export default () => {
return { content: 'Pong!', ephemeral: true }
}You can also return embeds and other Discord.js structures.
import { EmbedBuilder } from 'discord.js'
export default () => {
const embed = new EmbedBuilder()
.setTitle('Pong!')
.setDescription('Response time: 42ms')
return { embeds: [embed] }
}import { EmbedBuilder } from 'discord.js'
export default () => {
const embed = new EmbedBuilder()
.setTitle('Pong!')
.setDescription('Response time: 42ms')
return { embeds: [embed] }
}If you call interaction.reply() yourself, Sage steps aside and does not send a duplicate reply.
Discord showing three different bot responses: a plain text 'Pong!' reply, an ephemeral reply marked 'Only you can see this', and a rich embed response with title and description, all from the same bot
Deferred Replies
When a command takes longer than 250ms to respond, Sage automatically defers the interaction. This prevents Discord from showing an error to the user while your command finishes processing.
Without Sage, you must manually defer and edit the reply.
import type { ChatInputCommandInteraction } from 'discord.js'
export default async (interaction: ChatInputCommandInteraction) => {
await interaction.deferReply()
const data = await fetchSlowData()
await interaction.editReply(`Result: ${data}`)
}export default async (interaction) => {
await interaction.deferReply()
const data = await fetchSlowData()
await interaction.editReply(`Result: ${data}`)
}With Sage, return the result and deferral is handled for you.
export default async () => {
const data = await fetchSlowData()
return `Result: ${data}`
}export default async () => {
const data = await fetchSlowData()
return `Result: ${data}`
}Sage only defers when needed. Commands that respond within the buffer period skip deferral entirely, avoiding the "thinking..." indicator for fast responses.
Discord showing a bot interaction with the 'Bot is thinking...' deferred reply indicator visible, demonstrating automatic deferral for slow commands
Error Replies
In development mode, Sage sends detailed error messages when a command handler throws an exception. These messages include the file path, stack trace, and a time-locked log snapshot showing what happened leading up to the error.
Discord showing a Sage error reply in development mode with a red-tinted embed containing the error message, file path, stack trace excerpt, and a log snapshot section
Background Errors
Errors that occur outside of command or event handlers are forwarded to a debug channel when DISCORD_DEBUG_CHANNEL_ID is set in your environment variables. This prevents uncaught exceptions from crashing the bot while keeping you informed. See the Debugging page for more on setting up the debug channel.
Production Behavior
In production, Sage hides error details from users to keep channels clean. If you host with RoboPlay (a hosting platform for Robo.js projects), the dashboard provides a debugging section with full error details, stack traces, and log snapshots.
Configuration
Sage options can be set globally for all commands or per-command.
| Option | Type | Default | Description |
|---|---|---|---|
defer | boolean | true | Enable automatic deferrals |
deferBuffer | number | 250 | Milliseconds before deferring |
ephemeral | boolean | false | Make replies ephemeral |
errorChannelId | string | - | Channel for error messages |
errorMessage | string | - | Custom error message |
errorReplies | boolean | true | Show error replies |
Global Configuration
Set Sage options for your entire bot in the Discord plugin config file.
import type { DiscordConfig } from '@robojs/discordjs'
export default {
sage: {
defer: true,
deferBuffer: 500,
ephemeral: false
}
} satisfies DiscordConfigexport default {
sage: {
defer: true,
deferBuffer: 500,
ephemeral: false
}
}Per-Command Configuration
Override global settings for individual commands through the command's config export.
import { createCommandConfig } from '@robojs/discordjs'
export const config = createCommandConfig({
description: 'A slow command',
sage: {
defer: true,
deferBuffer: 1000
}
})import { createCommandConfig } from '@robojs/discordjs'
export const config = createCommandConfig({
description: 'A slow command',
sage: {
defer: true,
deferBuffer: 1000
}
})