Repository navigation
Discord Errors
Discord throws DiscordError for invalid configuration, local request
validation failures, documented vendor responses, and malformed payloads.
import { DiscordError, DiscordErrorCodes } from '@tundraconnect/discord/errors';
const error = new DiscordError('EMPTY_MESSAGE', { status: 400 });
console.log(error.message);
console.log(DiscordErrorCodes.EMPTY_MESSAGE);| Code | Meaning |
|---|---|
CONFIG_MISSING_CREDENTIALS |
Neither a webhook nor a botToken was supplied. |
CONFIG_AMBIGUOUS_CREDENTIALS |
More than one integration mode was supplied. |
CONFIG_INCOMPLETE_WEBHOOK |
Only one of webhookId / webhookToken was supplied. |
CONFIG_INVALID_WEBHOOK_ID |
webhookId isn't a Discord snowflake ID (17-20 digit numeric string). |
CONFIG_INVALID_WEBHOOK_TOKEN |
webhookToken isn't a single URL path segment (/, ?, #, ., .. rejected). |
CONFIG_INVALID_WEBHOOK_URL |
webhookUrl doesn't match Discord's documented webhook URL shape. |
CONFIG_INVALID_BOT_TOKEN |
botToken is present but not a non-empty string. |
REQUEST_VALIDATION_ERROR |
sendWebhookMessage()/sendChannelMessage() input failed local Guardian validation. |
MODE_MISMATCH |
Called a webhook-only method on a bot-mode client, or vice versa. |
GENERAL_ERROR |
Discord error 0 — general/malformed request body. |
UNKNOWN_CHANNEL |
Discord error 10003 — the channel doesn't exist or isn't visible. |
UNKNOWN_MESSAGE |
Discord error 10008 — referenced message doesn't exist. |
UNKNOWN_WEBHOOK |
Discord error 10015 — the webhook has likely been deleted. |
MISSING_ACCESS |
Discord error 50001 — the bot can't see this resource. |
EMPTY_MESSAGE |
Discord error 50006 — no content/embeds/etc. were sent. |
CANNOT_MESSAGE_USER |
Discord error 50007 — can't DM this user. |
CHANNEL_NOT_TEXT |
Discord error 50008 — the channel doesn't accept messages. |
MISSING_PERMISSIONS |
Discord error 50013 — the bot lacks the required permission. |
INVALID_AUTH_TOKEN |
Discord error 50014 — the configured bot token is invalid. |
INVALID_WEBHOOK_TOKEN |
Discord error 50027 — the configured webhook token is invalid. |
INVALID_FORM_BODY |
Discord error 50035 — the request payload failed Discord-side validation. |
MAX_ATTACHMENTS |
Discord error 30015 — too many attachments on the message. |
FILE_TOO_LARGE |
Discord error 50045 — an uploaded file exceeded the size limit. |
UNAUTHORIZED |
HTTP 401 with an undocumented/unparseable error body. |
FORBIDDEN |
HTTP 403 with an undocumented/unparseable error body. |
NOT_FOUND |
HTTP 404 with an undocumented/unparseable error body. |
RATE_LIMITED |
HTTP 429 — see retryAfter/global metadata to back off correctly. |
RESPONSE_ERROR |
A 2xx response whose body failed schema validation. |
SERVICE_UNAVAILABLE |
A 5xx response. |
TIMEOUT |
No complete answer within the timeout (context timeoutSeconds). |
NETWORK_ERROR |
The request failed before any response (DNS, TLS, connection reset). |
UNKNOWN_ERROR |
An unknown constructor code was supplied, or an unmapped 4xx status. |
TIMEOUT, NETWORK_ERROR, SERVICE_UNAVAILABLE and RATE_LIMITED are
transient: Discord gave no definite answer, so the same call may
succeed later. err.transient is true for exactly these and false for
every other code (a definite refusal or a misconfiguration retrying won't
fix). The set is also exported as DISCORD_TRANSIENT_CODES from
@tundraconnect/discord/errors.
In webhook mode a transient error or a RESPONSE_ERROR carries no
cause: RESTler's own error records the request URL, and the webhook token
is part of that URL. In bot mode the RESTler error is attached as cause
as usual.
Discord's numeric code (e.g. 50006) is reused verbatim in the
message templates above, per this repository's convention of preferring
documented vendor codes over inventing new ones. Codes without a Discord
number are connect-specific (configuration, local validation, or
HTTP-status-only fallbacks).
The resolved code is also available as a public, readonly error.code
property — branch on failure mode without matching against .message:
if (error instanceof DiscordError && error.code === 'RATE_LIMITED') {
// ...
}Use getContextValue() to read diagnostic metadata such as vendor,
status, vendorCode, vendorMessage, errors (Discord's nested
per-field validation tree on 50035 responses), or — for RATE_LIMITED
— retryAfter/global from Discord's
rate limit response.
A rate-limited request throws RATE_LIMITED. Two context values tell you what to
do next:
| Context | Meaning |
|---|---|
retryAfterSeconds |
Seconds the vendor asked you to wait, parsed by RESTler from Retry-After (delta seconds or an HTTP-date), X-RateLimit-Reset-After, RateLimit-Reset, or an epoch-seconds X-RateLimit-Reset. undefined when the response carried none — never a guess. |
retried |
Set only when maxRetryWait is configured: true if RESTler already waited once and was throttled again, false if it did not wait (the hint exceeded the cap, or there was no hint to wait on). |
Nothing is retried by default. Opt in with two client options (seconds,
each 0–120):
-
maxRetryWait— when a 429 carries a hint no longer than this, RESTler waits that long and retries once; otherwise it throwsRATE_LIMITEDimmediately.0disables the retry. -
defaultRetryWait— the wait used when a 429 carries no hint. Without it a hintless 429 is never retried: RESTler does not invent a delay. Only consulted whenmaxRetryWaitis set, and still capped by it.
| Code | Raised when |
|---|---|
WEBHOOK_INVALID_HEADERS |
A signature header is missing. |
WEBHOOK_TIMESTAMP_INVALID |
Unparseable timestamp, or outside the tolerance window. |
WEBHOOK_INVALID_KEY |
The Public Key is not a 64-hex-char Ed25519 key. |
WEBHOOK_SIGNATURE_INVALID |
Treat the request as forged. |
- Algolia
- AzureBlob
- CloudflareDNS
- CloudflareEmail
- CloudflareSaaS
- CloudflareTurnstile
- CoinGecko
- Discord
- DodoPayments
- GCS
- GoogleAnalytics
- GoogleCertificateManager
- GoogleWebRisk
- Kalshi
- ntfy
- OpenExchange
- OpenWeatherMap
- PayPal
- Polymarket
- Razorpay
- Resend
- S3
- SendGrid
- Sentry
- Slack
- Stripe
- Telegram
- Twilio
- UpstashRedis
- URLhaus