import { DiscordAPIError, RESTJSONErrorCodes } from 'discord.js';
export interface ToolError {
code: string;
message: string;
details?: string;
}
/**
* Handle Discord API errors and return user-friendly messages
*/
export function handleDiscordError(error: unknown): ToolError {
if (error instanceof DiscordAPIError) {
const code = error.code;
// Rate limit errors (status 429)
if (error.status === 429) {
return {
code: 'RATE_LIMITED',
message: 'Rate limit exceeded. Please wait before retrying.',
details: `Retry after: ${error.message}`,
};
}
// Permission errors
if (code === RESTJSONErrorCodes.MissingPermissions) {
return {
code: 'MISSING_PERMISSIONS',
message: 'Bot lacks the required permissions for this action.',
details: error.message,
};
}
if (code === RESTJSONErrorCodes.MissingAccess) {
return {
code: 'MISSING_ACCESS',
message: 'Bot does not have access to this resource.',
details: error.message,
};
}
// Not found errors
if (code === RESTJSONErrorCodes.UnknownGuild) {
return {
code: 'GUILD_NOT_FOUND',
message: 'Server not found or bot is not a member.',
details: error.message,
};
}
if (code === RESTJSONErrorCodes.UnknownChannel) {
return {
code: 'CHANNEL_NOT_FOUND',
message: 'Channel not found.',
details: error.message,
};
}
if (code === RESTJSONErrorCodes.UnknownMember) {
return {
code: 'MEMBER_NOT_FOUND',
message: 'Member not found in this server.',
details: error.message,
};
}
if (code === RESTJSONErrorCodes.UnknownRole) {
return {
code: 'ROLE_NOT_FOUND',
message: 'Role not found.',
details: error.message,
};
}
// Hierarchy errors (code 50028 is for role hierarchy issues)
if (code === 50028) {
return {
code: 'ROLE_HIERARCHY_ERROR',
message: 'Cannot modify this role due to role hierarchy.',
details: error.message,
};
}
// Ban errors
if (code === RESTJSONErrorCodes.UnknownBan) {
return {
code: 'BAN_NOT_FOUND',
message: 'User is not banned.',
details: error.message,
};
}
// General API error
return {
code: 'DISCORD_API_ERROR',
message: `Discord API error: ${error.message}`,
details: `Code: ${code}`,
};
}
if (error instanceof Error) {
return {
code: 'ERROR',
message: error.message,
};
}
return {
code: 'UNKNOWN_ERROR',
message: 'An unknown error occurred',
details: String(error),
};
}
/**
* Format a tool error for MCP response
*/
export function formatToolError(error: ToolError): string {
let result = `Error [${error.code}]: ${error.message}`;
if (error.details) {
result += `\nDetails: ${error.details}`;
}
return result;
}
/**
* Wrapper to catch and format errors for tool handlers
*/
export async function withErrorHandling<T>(
fn: () => Promise<T>,
): Promise<{ success: true; data: T } | { success: false; error: string }> {
try {
const data = await fn();
return { success: true, data };
} catch (error) {
const toolError = handleDiscordError(error);
return { success: false, error: formatToolError(toolError) };
}
}