Handling Errors
With Seyfert, you can handle errors in an organized way and treat them differently depending on the type of error.
Error when executing a command
This is the most common error and occurs when an error is thrown in the run method.
import { Command, type CommandContext } from "seyfert";
export class HandlingErrors extends Command {
async run(context: CommandContext) {
throw new Error("Error, ehm, lol player detected");
}
// : This responds with the previous error message: "Error, ehm, lol player detected"
async onRunError(context: CommandContext, error: unknown) {
context.client.logger.fatal(error);
await context.editOrReply({
content: error instanceof Error ? error.message : `Error: ${error}`
});
}
}Error when validating options
This error is thrown when an option fails in the value method.
const options = {
url: createStringOption({
description: 'how to be a gamer',
value(data, ok: OKFunction<URL>, fail) {
if (isURL(data.value)) return ok(new URL(data.value));
// This will trigger the onOptionsError method
fail('expected a valid URL');
},
})
};
@Options(options)
export class HandlingErrors extends Command {
async onOptionsError(
context: CommandContext,
metadata: OnOptionsReturnObject
) {
// : url: expected a valid URL
await context.editOrReply({
content: Object.entries(metadata)
.filter((_) => _[1].failed)
.map((error) => `${error[0]}: ${error[1].value}`)
.join("\n")
});
}
}Stop a middleware with an error
When a middleware returns a stop, Seyfert generates this error and stops the progress of the command being handled.
import { createMiddleware } from "seyfert";
export default createMiddleware<void>(({ context, next, stop }) => {
if (!Devs.includes(context.author.id)) {
return stop("User is not a developer");
}
next();
});import { Command, Middlewares, type CommandContext } from "seyfert";
@Middlewares(["OnlyDev"])
export class HandlingErrors extends Command {
async onMiddlewaresError(context: CommandContext, error: string) {
await context.editOrReply({
// : User is not a developer
content: error
});
}
}Missing member permissions
When a member doesn't have the required permissions specified in defaultMemberPermissions:
import { Command, type CommandContext, type PermissionStrings } from "seyfert";
export class HandlingErrors extends Command {
async onPermissionsFail(context: CommandContext, permissions: PermissionStrings) {
await context.editOrReply({
content: `You need the following permissions: ${permissions.join(', ')}`,
});
}
}Missing bot permissions
When the bot doesn't have the permissions specified in botPermissions:
import { Command, type CommandContext, type PermissionStrings } from "seyfert";
export class HandlingErrors extends Command {
async onBotPermissionsFail(context: CommandContext, permissions: PermissionStrings) {
await context.editOrReply({
content: `I need the following permissions: ${permissions.join(', ')}`,
});
}
}Lifecycle Hooks
Beyond error handlers, Seyfert provides lifecycle hooks for additional control:
import { Command, type CommandContext, type UsingClient } from "seyfert";
export class MyCommand extends Command {
// Called before middlewares run
async onBeforeMiddlewares(context: CommandContext) {}
// Called before options are parsed — useful for early deferral
async onBeforeOptions(context: CommandContext) {
await context.deferReply();
}
// Called after run() completes (with error if thrown)
async onAfterRun(context: CommandContext, error?: unknown) {}
// Called on internal Seyfert errors
async onInternalError(client: UsingClient, error: unknown) {}
}Default Error Handlers
Instead of defining error handlers on every command, you can set defaults in the Client constructor:
import { Client } from "seyfert";
const client = new Client({
commands: {
defaults: {
onRunError: (context, error) => {
context.editOrReply({ content: 'Something went wrong!' });
},
onOptionsError: (context) => {
context.editOrReply({ content: 'Invalid options provided.' });
},
onPermissionsFail: (context, permissions) => {
context.editOrReply({ content: `Missing permissions: ${permissions.join(', ')}` });
},
onBotPermissionsFail: (context, permissions) => {
context.editOrReply({ content: `I need: ${permissions.join(', ')}` });
},
onMiddlewaresError: (context, error) => {
context.editOrReply({ content: error });
},
onInternalError: (client, error) => {
client.logger.fatal(error);
},
},
},
// Defaults for component handlers
components: {
defaults: {
onRunError: (context, error) => {
context.editOrReply({ content: 'Component error!' });
},
},
},
// Defaults for modal handlers
modals: {
defaults: {
onRunError: (context, error) => {
context.editOrReply({ content: 'Modal error!' });
},
},
},
});Per-command error handlers override the defaults. If a command defines its own onRunError, the default won't be called for that command.