Error forwarding
Automatically forward unhandled errors to a Discord channel with interactive buttons.
The plugin catches unhandled errors (uncaught exceptions and unhandled promise rejections) and forwards them to a Discord channel. Each error appears as a rich embed with the full stack trace and two action buttons: Dismiss and Restart.
This only runs in development mode (robo dev). In production, the entire plugin is stripped from the build.
Setup
Point the plugin to a Discord text channel. You can do this with an environment variable:
DISCORD_DEBUG_CHANNEL_ID=1234567890123456789Or through the plugin config:
export default {
debugChannelId: '1234567890123456789'
}export default {
debugChannelId: '1234567890123456789'
}The config option takes priority over the environment variable.
How it works
The plugin registers an error hook at src/robo/error.ts. When the Robo framework catches an unhandled error, this hook fires and calls sendDebugError() which:
- Checks that the Robo is running in dev mode
- Reads the debug channel ID from config or env
- Gets the Discord client from
@robojs/discordjs - Sends a red embed to the channel with the error stack trace
- Attaches Dismiss and Restart action buttons
If any step fails (no channel configured, client not ready, channel not found), the function returns false silently. Errors during forwarding don't crash the process.
Interactive buttons
Each error embed includes two buttons:
| Button | Action |
|---|---|
| Dismiss | Deletes the error message from the channel |
| Restart | Replies with "Restarting..." then triggers a process restart |
The restart behavior depends on how the Robo is running:
robo devmode — Sends a{ type: 'restart' }IPC message to the parent process for a graceful restart- Standalone — Calls
process.exit(0)and relies on a process manager to restart
Role pinging
Notify your team when errors occur by configuring a role to ping:
export default {
debugChannelId: '1234567890123456789',
errorPingRoleId: '987654321098765432'
}export default {
debugChannelId: '1234567890123456789',
errorPingRoleId: '987654321098765432'
}When an error is forwarded, the message includes a role mention (<@&roleId>) that pings all users with that role.
Programmatic usage
You can also send errors to the debug channel from your own code:
import { sendDebugError } from '@robojs/dev'
try {
await riskyOperation()
} catch (error) {
const sent = await sendDebugError(error)
if (!sent) {
console.error('Failed to forward error:', error)
}
}import { sendDebugError } from '@robojs/dev'
try {
await riskyOperation()
} catch (error) {
const sent = await sendDebugError(error)
if (!sent) {
console.error('Failed to forward error:', error)
}
}For replying to interactions with error embeds, use printErrorResponse:
import { printErrorResponse } from '@robojs/dev'
export default async function (interaction) {
try {
await someCommand(interaction)
} catch (error) {
await printErrorResponse(error, interaction)
}
}import { printErrorResponse } from '@robojs/dev'
export default async function (interaction) {
try {
await someCommand(interaction)
} catch (error) {
await printErrorResponse(error, interaction)
}
}This handles all interaction states — deferred, already replied, or fresh — and sends an ephemeral red embed with the error message.
See the API reference for full function signatures.
Stack trace truncation
Discord embeds have a 4000-character limit for descriptions. Stack traces longer than this are truncated automatically.
