Field notes
Twilio fix guides
Most Twilio failures are a setting, not a bug. A number is still pointing at the demo TwiML URL, a campaign never finished registering, a webhook has no fallback. None of it raises an exception in your code — the message simply does not arrive. Each note here explains one such problem and gives you a script that finds it through the API.
A script here holds a credential to an account that can send messages and charge you for them. So these read, they tell you exactly what is wrong, and they print the repair: the resource, the field, the value. You run it.
Give them a Twilio API Key with read access rather than the account auth token. If a read-only key leaks, somebody learns your phone numbers; if the auth token leaks, somebody sends from them.
Twilio
A phone number still points at Twilio's demo TwiML
Callers hear the Twilio demo greeting instead of your app. The webhook answers 200, every call is marked completed, and error monitoring never sees it.
Inbound SMS disappears into a number with no sms_url
The Messaging Service has an inbound URL and it is being ignored. Deferring to the sender's webhook means a blank sms_url on the number drops every reply.
A Messaging Service with no A2P campaign fails US sends
us_app_to_person_registered is false, so every US 10DLC send returns 30034. The service accepts numbers and API calls happily; only the message fails.
A number with no fallback URL drops the call when yours 500s
Twilio calls the fallback URL only when the primary handler errors. With none configured, one 11200 during a deploy is a lost customer call.
13224: Twilio refuses the number your Dial verb asked for
The leg never rings and the parent call carries on to the action URL. The destination is national format, a premium range, or a number that does not exist.
Answering machine detection is routing humans to voicemail
answered_by comes back machine_start or unknown on calls a person picked up. The connect rate falls and every call still reads as completed.
A recording row says absent and there is no media behind it
The Recording resource exists, status is absent, error_code is set and the media URL 404s. The call completed normally, so nothing else looks wrong.
21215: dialing permissions block a country you sell into
Calls to one country fail with 21215 or 13227 while the identical code works at home. Subaccounts fail on their own when inheritance is off.
High risk dialing prefixes left open to toll fraud
Nothing fails. The toll-fraud and special-service ranges stay callable on an upgraded account, and one compromised endpoint runs five figures overnight.
Verify runs with lookup_enabled false, so landlines are billed
skip_sms_to_landlines needs lookup_enabled and it is off by default. Verify sends into landlines at full price and 60205 never reaches your logs.
An invalid or uncovered number: 21211 on send, 60600 on Lookup
Twilio does no fuzzy parsing. A national-format number stored years ago fails with 21211, and a range no carrier was ever assigned comes back 60600.
11200 on the TwiML fetch: the call fails, not just a receipt
Anything outside 2xx is a retrieval failure. On an inbound handler that is a dropped call or a lost message, not a delivery receipt that went missing.
12200: TwiML that parses, fails the schema, and is skipped
The document is well formed, so 12100 never fires. The verb is miscased, the schema rejects it, and Twilio logs the whole thing at warning.
A rejected WhatsApp content template blocks every send
whatsapp.status is rejected and 63040 comes back on every send. Outside the 24 hour window an approved template is the only thing that will deliver.
Carrier filtering drops your SMS silently with error 30007
Messages go undelivered with error_code 30007. Nothing arrives, you are billed anyway, and the Messages list has no error filter to find them with.
Sends to recipients who texted STOP bounce with 21610
Twilio remembers the opt-out and your database does not, so every send to that number is rejected with 21610 and the compliance record keeps growing.
SMS to a landline fails with 30006 and retrying never helps
Error 30006 and 21614 mean the destination cannot receive SMS at all. The retry loop bills you forever; Lookup line type is what settles the argument.
Messages stay queued or accepted and never reach a final state
Status sits at queued or accepted for hours with no error_code. Part of it is throughput starvation, part is a scheduled send, and sent is not a failure.
A2p campaign is FAILED and errors[] names the rejected field
campaign_status is FAILED and every US send returns 30034. The errors[] array names the exact attribute that was rejected, and nobody reads it.
An A2P brand stuck at FAILED blocks every campaign under it
BrandRegistration.status is FAILED, so no campaign can attach and every US send is 30034. The reason is in errors[], not in the deprecated prose fields.
An a2p campaign parked at IN_PROGRESS is not a live campaign
campaign_status sits at IN_PROGRESS for weeks, campaign_id is null, and the launch ships anyway. Nothing errors, and every US send returns 30034.
An unverified toll-free number is blocked, not throttled
Every US and CA message from an unverified +1 8XX number fails 30032, and you are billed for the attempts. Pending review is a blocked state too.
Status callback failures with 11200 leave delivery state blind
Twilio delivered the message and your database still says queued. The 11200 alerts name the failing endpoint; the Messages list is the state that is true.
Twilio cannot open a TCP connection to your webhook (11205)
11205 means the handshake never completed, so your access log is empty. Whether that is a firewall, a dead host or a private address is one read away.
An expired webhook certificate fails every request with 11236
11236 arrives at a sharp timestamp boundary and every number on that hostname breaks at once. Alerts are kept 30 days, which bounds what you can see.
A webhook hostname with no public DNS record fails with 11210
11210 is a name Twilio cannot resolve from the public internet: an internal zone, a dead developer tunnel, or a record that was never published.
A number with an Application SID ignores its own voice_url
When voice_application_sid is set it wins outright and voice_url is ignored, so every edit to the number changes nothing and calls keep hitting an old app.
An empty sender pool fails every send with error 21704
The Messaging Service exists and looks configured, but no sender was ever added, so Twilio has no From to pick and rejects before any carrier hop.
A voice-only From number fails every SMS with error 21606
21606 says the From is not a message-capable Twilio number for this account. Usually it is voice-only, on another subaccount, or not in E.164 format.
No status callback means delivery failures never reach you
Messages.create returns queued and your database records a success. Terminal status and error_code arrive only by status callback or Event Streams.
SMS Pumping Protection blocks legitimate OTPs with 30450
Sends to one country start failing with error_code 30450, then recover on their own. The Messages list has no error filter, so nothing catches the window.
Error 21617: the rendered message body exceeds 1600 chars
Error 21617 rejects the send before a Message row exists, so it never appears in the Messages list. Monitor Alerts is the only read-only path to it.
One smart quote triples your segment count and your bill
One smart quote forces UCS-2 for the whole body: 70 characters a segment instead of 160. Nothing errors, num_segments triples and so does the bill.
Queue overflow 30001: a send loop outruns one long code
Bulk sends through one long code fail with error_code 30001. The queue holds about ten hours of segments at 1 MPS, and the producer outruns it.
Phone numbers with no traffic still bill every month
Idle Twilio numbers rent forever. Compare each number's inbound and outbound activity against its monthly rate to get a figure somebody can act on.
A trial account rejects multi-segment messages with 30044
Short test messages send. Real templates fail with 30044 because a trial account caps length, and one emoji halves the per-segment budget to 70 characters.
Outbound messaging is off, so every send fails with 30037
One subaccount returns 30037 on every send while the others are fine. Read Accounts.json for status, attribute the failures by account_sid, and find it.
Recycled numbers send OTPs to whoever owns them now
Carriers reissue deactivated numbers. Pull Twilio's Deactivations feed, reconcile it against your contact list, and find the codes going to a stranger.
Verify conversion collapses in one country: SMS pumping
Verify spend jumps, mostly to one country, and almost none of those codes are ever entered. No error code: the sends succeed and are billed.
A Verify Service with zero rate limits configured
Verify's built-in protection is per phone number only. With no Service Rate Limits, one script rotating destinations from one IP is entirely unthrottled.
Fraud Guard blocked the prefix, so real users get 60410
One country cannot sign up for twelve hours. Fraud Guard saw pumping-shaped traffic on a prefix and blocked it, and legitimate users share that prefix.
Verify sends SMS to a landline: 60205, or just silence
A slice of users never receive their code. The destination is a landline or fixed VoIP range that cannot receive SMS, and Verify bills the attempt anyway.
A SIP trunk with no disaster recovery URL loses every call
disaster_recovery_url is empty by default. Nothing reports it until the PBX goes down, and then inbound calls to the trunk are dropped with no fallback.
A SIP Domain with no auth_type accepts no traffic at all
A SIP Domain routes traffic only when auth_type is IP_ACL or CREDENTIAL_LIST. Left undefined, every INVITE is refused before your voice_url is fetched.
Dial rejected with 13214 on a passed-through caller ID
A Dial with no explicit callerId forwards whatever the inbound leg carried. When a carrier delivers a malformed From, the outbound leg is rejected as 13214.
A rising share of outbound calls end in status failed
No single error code explains it. The Calls resource is the only place a failure rate rather than an event is visible, and only if you fetch the denominator.
No Usage Trigger, so overspend runs with nothing watching
Usage Triggers are the only server-side spend alarm Twilio has, and an account starts with none. Find that, and the dead triggers, before the invoice does.
No API keys exist, so the auth token is the credential
The auth token authenticates every service and signs every webhook, so rotating it is account-wide and instant. Find out whether anything still holds it.
Years-old API keys are still live with nobody owning them
API keys never expire and carry no last-used timestamp. Find the nameless ones, and know what deleting one takes down before you delete it.
An approved regulatory bundle is counting down to expiry
The bundle proving your address to a regulator has a valid_until. It passes, the bundle is auto-rejected, and the numbers attached to it go non-compliant.
Signature validation rejects Twilio with 403 behind a proxy
It worked on the laptop and 403s in production. The signature covers the URL Twilio called, not the one your proxy handed the app.
A TwiML response with the wrong Content-Type fails with 12300
The body is valid TwiML and Twilio never parses it. 12300 is decided on the response header, and a missing header shows up as 502 instead.
TwiML that is not well-formed XML fails with 12100
12100 is an XML parser refusing your document. Usually one blank line before the declaration. The bytes Twilio received are one fetch away.
A TwiML response over 64 kB drops the call with 11750
11750 is usually not a big TwiML document. It is an HTML stack trace returned where TwiML was expected, and the giveaway is in the body.
A Studio Flow left in draft, so your edits are live nowhere
Studio keeps a published revision and a draft. The Console shows the draft; a number pointed at the Flow runs the published one. Your change is live nowhere.
A published Studio Flow that no phone number points at
Publishing a Flow does not attach it to anything. The Flow has zero executions while inbound calls and SMS still hit the old webhook, or Twilio's demo TwiML.
A conversation webhook with no URL fails every event: 50369
Error 50369 says the conversation webhook URL was not provided. The webhook exists, it is attached, and configuration.url is empty, so no event ever leaves.
A failed Event Streams sink drops events and nothing says so
A sink whose status is failed has stopped delivering. Messages and calls carry on as before, downstream analytics quietly stop, and no error code is raised.
SMS Geo Permissions are off for the destination country
Error 21408 on every message to one country. There is no API that reads this setting, so the traffic is the only evidence you can get.
An alphanumeric sender ID is unregistered where you send
30040 and 30041 arrive only from the destination carrier, so the API returned 201 and the sender looks fine. Find which sender IDs die in which country.
US and Canadian numbers with no registered E911 address
There is no error until somebody dials 911. Then the call reaches a national centre that has to ask where you are, and the per-call fee arrives later.
A short code used outside its own country fails 21612
Short codes are licensed nationally. A pool that mixes one with long codes will hand it an international message, and that send is rejected 21612 or 21606.
An A2P brand parked at PENDING for weeks with no callback
The brand never failed and never approved. status is PENDING or IN_REVIEW, tcr_id is null, and the status callback that was supposed to tell you was missed.
A SUSPENDED brand suspends every campaign underneath it
Traffic that worked yesterday returns 30033 and the campaign reads SUSPENDED. The cause is one level up: the brand was suspended and the cascade is silent.
Brand failed 30799: the EIN does not match the legal name
The commonest Standard brand rejection. TCR checks the EIN against public tax records and needs an exact match, so a DBA or an old address fails it.
An approved brand with no trust score is throttled to the floor
The brand is APPROVED, campaigns are still rejected for AT&T and throughput sits at the lowest tier. brand_score is null because secondary vetting never ran.
Error 11220: the TLS handshake with your webhook never completes
11220 is a refusal during negotiation, before any certificate is presented. Browsers still load the URL because they offer things Twilio's client does not.
Error 11237: your webhook sends a chain Twilio cannot verify
A missing intermediate or a private CA leaves Twilio with no path to a trusted root. Browsers hide the fault by fetching the part your server left out.
Error 11206: Twilio cannot parse your webhook's HTTP response
Your server logs a 200 and Twilio logs a protocol violation. What broke the parse is in response_headers, which only the single-alert fetch returns.
Number webhooks on http, a private address or a dev tunnel
Three faults in one field: cleartext signatures, an address Twilio can never reach, and a tunnel that dies with the laptop. All visible in configuration.
The balance is one busy hour from a 20005 suspension
Twilio is prepay: at zero the account is suspended, not throttled. Compare Balance.json against your real daily burn and count the days of runway.
A suspended subaccount, so one tenant's traffic 20005s
Twilio notifies nobody when a subaccount is suspended. List Accounts.json by status with parent credentials and find the tenant that quietly stopped.
REST concurrency exhausted, so bursts come back 20429
Twilio caps concurrent REST requests per account and the ceiling is in no response body. Sample Twilio-Concurrent-Requests at peak, before it bites.
Recordings billed for storage until something deletes them
Twilio stores call recordings forever and bills per stored minute. Read the accumulated recordings spend and the oldest file, not the number of files.
Error 30003 is a handset that is off, not a dead number
30003 is transient: retry once and most of it delivers. But a fifth of one sender's traffic failing this way is a carrier block wearing a handset error code.
Error 30005 is permanent: the carrier has no such number
30005 means the number does not exist on the carrier. Retrying is billed and can never work, so the finding is which contacts to delete rather than requeue.
Error 30036: messages expire in the queue before they send
A ValidityPeriod shorter than the real queue wait kills messages before their turn. 30045 and 30012 are the request-time cousins with a different fix.
Error 30019: the MMS is too big for the carrier, not for Twilio
Twilio accepts 5 MB and carriers stop between 300 KB and 3.5 MB, so the same image delivers to one recipient and fails for the next with error 30019.
A suspended campaign returns 30033 and the sends keep coming
Every US message fails with 30033 and the producer has not been told. The Messages list dates the suspension and shows what your code did after it.
30022 when sends outrun the throughput the carrier assigned
Intermittent 30022 at peak and nothing wrong at 3am. Compare your busiest minute against rate_limits on the campaign before asking for more throughput.
A 10DLC number outside the sender pool is never registered
The brand is APPROVED and the campaign VERIFIED, and this number still 30034s. A2P registration attaches through the pool, and this number is not in one.
30035 and 30024 are a clock, not a configuration mistake
A new sender fails for up to 24 hours while carrier routing catches up. Removing and re-adding the number restarts the clock instead of ending it.
A Verify Service issuing four-digit codes to production
Four digits is ten thousand codes and each verification allows five checks. No error code will ever mention it, and nobody has looked at the field since.
60202: a verification that burned all five check attempts
The code is right and the check still fails. A handler that fires on every keystroke spends the five-attempt budget before the user has finished typing.
60203: a resend button with no cooldown burns five sends
Verify allows five sends per verification. A resend with no cooldown, or a retry that treats slow SMS as failure, drains them in seconds and bills each one.
OTP codes sent without the do-not-share warning line
do_not_share_warning_enabled is off by default, so the SMS is a bare code. A custom default template can drop the line even when the flag is on.
Dial fails with 32009 because the SIP endpoint is not there
32009 means the user you dialled holds no registration on the domain. A dropped REGISTER refresh and a username that never matched look identical.
32011: Twilio cannot reach your SIP infrastructure
Twilio got no answer, a SIP 5xx, or something it could not parse from your origination URI. Redundancy that all resolves to one host is not redundancy.
A trunk sheds calls at its CPS limit and the average hides it
32001 is a ceiling hit inside one second. Failures cluster in the first moments of a batch and disappear into any hourly rate you compute afterwards.
A carrier blocks your caller ID and 32017 is the only notice
32017 is a terminating carrier refusing a number on reputation. The score is built from answer rate and call duration, both of which you can read.
A rejected regulatory bundle blocks every number purchase
The bundle failed review, not the clock. Until somebody reads its item assignments and resubmits it, no number can be bought in that country.
A bundle is noncompliant on a field only Evaluations names
The bundle will not submit and the status says nothing useful. The per-requirement breakdown naming the exact failing field is in a subresource.
One rejected Trust Hub profile fails brands and toll-free
A brand rejection and a toll-free rejection that make no sense together usually share one cause: the Customer Profile both of them hang off.
A rejected toll-free verification is fixable or it is not
TWILIO_REJECTED carries a coded reason and an edit window. Correcting the named fields works for some codes and can never work for others.
The account itself is suspended, so every send fails with 20005
Status on the top-level account, not on a subaccount. One GET answers it, and the 30002s on the queued backlog say when it started.
A production integration is still running on a trial account
Trial accounts reach three lifetime-verified numbers and prefix every message body. Count how much real traffic is already aimed at one.
The trial account's three verified numbers are spent
A teammate's phone gets 21608 while the first developer's still works. The trial verification quota is three numbers for the account's lifetime.
20003 on a read key: dead credential or a real boundary
A read-only key gets 20003 on Keys and Accounts by design. Tell that boundary apart from a wrong SID, a stale key, or a suspended account.
A Studio Flow whose definition is invalid, so widgets never run
The Console draws the canvas and valid is false. A transition to a deleted widget leaves the definition uncompilable, and executions stop at the break.
Conversations webhooks fire for nothing when filters are empty
post_webhook_url is set and correct and nothing ever arrives. Conversations delivers only the events named in filters, and an empty list names none of them.
Five conversation webhooks is the cap, and the sixth is rejected
Error 50361 lands on whichever integration deployed last. The conversation already holds five webhooks, and two of them often point at the same URL.
A Sync webhook rejected as invalid, or never called at all
Error 54051 is the loud half. The quiet half is webhooks_from_rest_enabled, off by default, so every change your own server makes over REST calls nothing.
An SMS number that belongs to no Messaging Service
No error code, just unpooled sending: no sticky sender, no geomatch, no long code failover, and A2P registration that attaches through a pool.
Error 21703: the pool has senders but none reach the To
Sender selection needs a pool member matching the destination country and message type. A pool with no US number fails every US send with 21703.
Two toll-free numbers in one sender pool get both blocked
Carriers read several toll-free senders in one Messaging Service as snowshoeing and block them. Twilio's guidance is one toll-free number per service.
A ten hour validity period delivers passcodes nobody wants
validity_period defaults to 36,000 seconds, so a queued passcode can wait ten hours and then arrive, after the user gave up and requested three more.
Error 14107: an auto-reply loop trips the SMS rate limit
Twilio caps outbound at 30 messages between the same two numbers in 30 seconds. The limit is the symptom; a handler answering its own answer is the bug.
Numbers still pinned to the 2008-08-01 API version
A number carries its own api_version, fixed when it was bought. A 2008 pin serves the old schema forever, without the fields the documentation promises.
Programmable Chat is still in use past its end of life
Nothing breaks on a deprecation date, so the only signal is that you are still calling it. Count the Chat services, then find out what still depends on them.
Notify services still on the account after Notify's EOL
Notify reached end of life and push stopped arriving, with no error anywhere. The services still exist in the API. The question is what is still bound to them.
Call recordings stored without encryption at rest
Voice Recording Encryption is opt-in and not retroactive. Read encryption_details across the sample to learn when it was on and what is still in the clear.
Nothing subscribes to error logs, so failures age out
Debugger alerts are kept 30 days and pushed nowhere unless something subscribes. Read the Event Streams subscriptions and what each one actually carries.
A Sole Proprietor brand blocked by an OTP nobody answered
The brand never rises to VERIFIED because the owner never replied to the SMS passcode. The reply window is 24 hours and nothing tells you it closed.
Extra numbers on a Sole Prop campaign never leave UNREGISTERED
A Sole Proprietor brand allows one campaign holding one number. Adding more never errors: the extras stay UNREGISTERED and 30034 arrives at random.
T-Mobile caps daily segments per brand, not per campaign
Sends stop mid-afternoon with 30023 and resume at midnight Pacific. The ceiling belongs to the brand and every campaign under it shares one pool.
A rejected toll-free record's edit window closes on a clock
edit_allowed is true and edit_expiration is days out. Miss it and the in-place correction is gone: only a fresh submission, at the back of the queue.
A link shortening certificate expires and short links break
A bring-your-own certificate on a link-shortening domain has a fixed date_expires and is not renewed for you. 30131 warns, then 30120 breaks the sends.
These are the ones I keep hitting. If yours is broken in a way none of them describes, tell me on LinkedIn — it is usually how the next note gets written.