Errors
Catch FluxerError, read ErrorCodes, and turn API failures into useful replies.
User-facing validation and not-found cases in @fluxerjs/core throw FluxerError with an ErrorCodes value. Prefer checking the code over scraping the message string.
Catch and inspect
import { FluxerError, ErrorCodes } from '@fluxerjs/core';
try {
await guild.fetchMember(userId);
} catch (err) {
if (err instanceof FluxerError && err.code === ErrorCodes.MemberNotFound) {
await message.reply('That user is not in this server.');
return;
}
console.error(err);
await message.reply('Something went wrong.');
}FluxerError often wraps a REST failure in cause. HTTP status may live on err.statusCode or err.cause?.statusCode depending on the path.
Control automatic retries
REST retries GET, HEAD, and OPTIONS requests up to three times by default. Other methods run once so a failed mutation is not repeated automatically.
Use retryPolicy when a mutation is safe to retry:
import { Client } from '@fluxerjs/core';
const client = new Client({
rest: {
retries: 3,
retryPolicy: ({ method, routeKey, defaultRetries }) => {
if (method === 'POST' && routeKey === '/channels/:id/messages') return defaultRetries;
return undefined;
},
},
});The policy runs once per request. Return a non-negative integer to set the retry count. Return undefined to keep the normal default, which is the configured retries value for safe methods and zero for mutations. The callback receives the method, the configured retry count, and a sanitized routeKey for matching.
routeKey replaces Snowflake IDs and webhook tokens, drops queries and fragments, and reduces absolute URLs to their origin plus /:external. It never includes request headers or bodies. Custom relative routes may still contain application-specific path segments, so use routeKey for matching rather than logging.
Automatic retries cannot resolve an uncertain mutation. A timeout may happen after Fluxer accepted the request. Store the unknown result and reconcile it before retrying.
Authentication on absolute URLs
Relative routes and absolute URLs on the configured API origin include the bot token by default. Other absolute URLs do not.
Pass auth: true only when the other origin is trusted and should receive the same token.
Common codes
Exact members live on ErrorCodes. Ones you will hit early:
| Situation | Typical code |
|---|---|
| Channel / message / member missing | *NotFound family |
| Bad fetch limit | INVALID_FETCH_LIMIT |
| Validation on a public method | named code for that check |
Builders (EmbedBuilder, etc.) may still throw plain RangeError for length limits. That is intentional.
Pattern for commands
Keep handlers boring: try the mutation, map known codes to a short reply, log everything else.
try {
await guild.ban(userId, { reason, deleteMessageDays: 1 });
await message.reply(`Banned <@${userId}>.`);
} catch (err) {
if (err instanceof FluxerError && err.code === ErrorCodes.MemberNotFound) {
await message.reply('User not found.');
return;
}
throw err; // or log + generic reply
}See moderation-bot for this pattern in a full bot.