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

javascript
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:

javascript
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:

SituationTypical code
Channel / message / member missing*NotFound family
Bad fetch limitINVALID_FETCH_LIMIT
Validation on a public methodnamed 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.

javascript
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.