Twilio Errors - TundraSoft/tundra-connect GitHub Wiki
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);| 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).
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. |
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 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. |