Twilio Errors - TundraSoft/tundra-connect GitHub Wiki

Twilio Errors

Twilio throws TwilioError for invalid configuration, local request validation failures, documented vendor responses, and malformed payloads.

import { TwilioError, TwilioErrorCodes } from '@tundraconnect/twilio/errors';

const error = new TwilioError('INVALID_TO_NUMBER', { to: '123' });
console.log(error.message);
console.log(TwilioErrorCodes.INVALID_TO_NUMBER);

Codes

Code Meaning
CONFIG_INVALID_ACCOUNT_SID accountSid is missing or doesn't match ^AC[0-9a-fA-F]{32}$.
CONFIG_INCOMPLETE_API_KEY Only one of apiKeySid / apiKeySecret was supplied.
CONFIG_MISSING_CREDENTIALS Neither authToken nor a complete API Key pair was supplied.
INVALID_REQUEST Request options failed local Guardian validation (sendMessage(), createCall(), getCall(), listCalls(), updateCall(), or deleteCall()).
AUTH_FAILED Twilio error 20003 — bad Account SID/Auth Token or API Key.
RATE_LIMITED Twilio error 20429 — too many requests / concurrency limit.
INVALID_TO_NUMBER Twilio error 21211 — to is not a valid phone number.
NON_SMS_CAPABLE_FROM_NUMBER Twilio error 21606 — from is not SMS-capable.
UNVERIFIED_TO_NUMBER Twilio error 21608 — to is unverified (trial accounts, SMS).
UNSUBSCRIBED_RECIPIENT Twilio error 21610 — to has unsubscribed from this sender.
UNROUTABLE_TO_NUMBER Twilio error 21612 — to is unroutable.
NON_SMS_CAPABLE_TO_NUMBER Twilio error 21614 — to is not SMS-capable.
INTERNATIONAL_PERMISSION_DENIED Twilio error 21408 — international permissions not enabled.
INVALID_FROM_NUMBER Twilio error 21212 — from is not a valid phone number, Alphanumeric Sender ID, or approved WhatsApp Sender.
UNREACHABLE_TO_NUMBER Twilio error 21214 — the to phone number cannot be reached (Voice).
UNVERIFIED_TO_NUMBER_VOICE Twilio error 21219 — to is unverified (trial accounts, Voice).
TWIML_FETCH_FAILED Twilio error 11200 — Twilio couldn't retrieve a successful response from the call's TwiML/webhook URL.
ACCOUNT_SUSPENDED Twilio error 10001 — the account is not active.
RESPONSE_ERROR A 4xx response parsed, but its vendor code is undocumented here.
SERVICE_UNAVAILABLE A 5xx response, or a response body that failed to parse at all.
TIMEOUT Twilio did not answer within the client timeout (timeoutSeconds in context).
NETWORK_ERROR fetch failed before any response (DNS, TLS, connection reset); the transport error is the cause.
UNKNOWN_ERROR An unknown constructor code was supplied.

INVALID_TO_NUMBER (21211) and AUTH_FAILED/RATE_LIMITED (20003/20429) are shared across the Messages and Calls resources — Twilio documents them identically for both, and TwilioError's vendor-code mapping isn't endpoint-specific. UNVERIFIED_TO_NUMBER (21608, SMS) and UNVERIFIED_TO_NUMBER_VOICE (21219, Voice) are kept as distinct codes because Twilio assigns them different numeric codes with different messages, even though both describe "trial account, recipient not verified".

The resolved code is also available as a public, readonly error.code property — branch on failure mode without matching against .message:

if (error instanceof TwilioError && error.code === 'RATE_LIMITED') {
  // ...
}

Use getContextValue() to read diagnostic metadata such as vendor, status, vendorCode, vendorMessage, or moreInfo (Twilio's error reference URL, when the vendor supplies one).

Transient failures

TIMEOUT, NETWORK_ERROR, SERVICE_UNAVAILABLE and RATE_LIMITED mean "no answer yet": retrying later can help. Every other code is a definite refusal or a misconfiguration that retrying will not fix. Branch on the readonly err.transient, which is true for exactly these four, rather than listing codes yourself. The set is also exported as TWILIO_TRANSIENT_CODES from @tundraconnect/twilio/errors.

import { TwilioError } from '@tundraconnect/twilio/errors';

declare function callTheClient(): Promise<unknown>;

try {
  await callTheClient();
} catch (err) {
  if (err instanceof TwilioError && err.transient) {
    // queue it and try again later
  }
  throw err;
}
Context Present on Meaning
timeoutSeconds TIMEOUT The deadline that was missed, in seconds.

Backing off after a 429

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 throws RATE_LIMITED immediately. 0 disables 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 when maxRetryWait is set, and still capped by it.

← Back to Twilio

Webhook codes

Code Raised when
WEBHOOK_INVALID_HEADERS A required signature header is missing.
WEBHOOK_INVALID_AUTH_TOKEN No account auth token available — pass authToken under API-key auth.
WEBHOOK_SIGNATURE_INVALID Treat the request as forged.
⚠️ **GitHub.com Fallback** ⚠️