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 requests retry up to three times by default. For non-idempotent or durably orchestrated mutations, use a request-aware policy to disable automatic retries while retaining them for reads:

javascript
import { Client } from '@fluxerjs/core';

const client = new Client({
  rest: {
    retries: 3,
    retryPolicy: ({ method, defaultRetries }) =>
      method === 'GET' ? defaultRetries : 0,
  },
});

The policy runs once per logical request and returns its retry budget. Return undefined to retain the configured default. It receives the request method, a sanitized routeKey for matching, and the default retry count. The exact caller-supplied route is not included as a separate field: Snowflake IDs are replaced by :id, webhook credentials are replaced by :token, query parameters are omitted, and absolute URLs are reduced to their origin plus /:external. Request bodies and headers are never exposed. Both configured and policy-selected retry counts must be non-negative safe integers.

Treat routeKey as matching metadata rather than a logging field when using custom relative routes, whose application-specific path segments cannot be classified by the SDK.

Disabling automatic retries does not make an ambiguous mutation safe to replay. A timeout or transport failure can occur after the server applied the request, so durable applications should persist an unknown outcome and reconcile it explicitly.

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.