LLOQU
ProductPricingBlogDocsLogin

On this page

What does Twilio error 31000 mean?How do I find the real error behind 31000?The most common fix: your TwiML App and Voice URLWhich 31xxx error is hiding behind your 31000?Stop the error-retry loopDoes 31000 happen on iOS and Android too?A five-minute debugging checklistFAQDelete the four causes
All articles
TwilioVoice SDKErrors

Twilio Error 31000: What It Means and How to Fix It

Twilio error 31000 is a generic Voice SDK failure that hides the real cause. How to surface the underlying error and fix the four problems behind it.

Alloqui TeamAug 11, 20268 min read
On this page
What does Twilio error 31000 mean?How do I find the real error behind 31000?The most common fix: your TwiML App and Voice URLWhich 31xxx error is hiding behind your 31000?Stop the error-retry loopDoes 31000 happen on iOS and Android too?A five-minute debugging checklistFAQDelete the four causes
Back to all articles
LLOQUAlloqui

Product

  • Features
  • Pricing
  • Blog

Developers

  • Documentation
  • @alloqui/dialer on npm

Company

  • Contact

Legal

  • Privacy
  • Terms

© 2026 Alloqui

Twilio error 31000 ("General error" / "Generic error") is the Voice SDK's catch-all code: something failed during call setup or mid-call, and no more specific 31xxx code was generated. It tells you that something broke, never what — the real cause is almost always one of four things: a misconfigured TwiML App, a failing voice webhook, a token problem, or a network interruption. This guide shows you how to surface the underlying error in about two minutes, then fix each cause.

What does Twilio error 31000 mean?

31000 is the generic error of Twilio's Programmable Voice 310xx series. Twilio's own documentation says a "non-specific condition occurred in the Voice SDK or platform during call setup or operation" and points you to the Debugger for details. In practice it is a symptom code, not a diagnosis: the SDK hit a failure it couldn't classify, so it fell back to 31000. That's also why searching the code alone rarely helps — two apps throwing 31000 usually have two different bugs. The fix always starts with extracting the real error underneath.

How do I find the real error behind 31000?

Two places, in order.

1. Log the full error object in the SDK. As of the current @twilio/voice-sdk (v2), the error event hands you a TwilioError with more than just a code:

import { Device } from '@twilio/voice-sdk';

const device = new Device(token, { logLevel: 1 }); // debug logging on

device.on('error', (twilioError, call) => {
  console.log(twilioError.code);          // 31000
  console.log(twilioError.description);
  console.log(twilioError.explanation);
  console.log(twilioError.originalError); // ← the underlying failure, when present
});

originalError is the field that turns "general error" into something actionable — a WebSocket close, a rejected HTTP request, a media failure. With logLevel: 1 the SDK also prints its signaling traffic to the console, which shows the last thing that happened before the failure.

2. Check the Twilio Debugger. In the Console go to Monitor → Logs → Errors. Find the entry matching your failed call's timestamp and open it — Twilio logs the server-side view there, including webhook requests that failed and what your server returned. Cross-reference the Call SID from Monitor → Logs → Calls to see the full request/response cycle for that specific call.

If the Debugger shows a different error code (11200, 12100, 31205…), stop debugging 31000 and fix that code instead. 31000 was just the messenger.

The most common fix: your TwiML App and Voice URL

The most common source of 31000 on outbound browser calls is the TwiML Application the call routes through. Verify three things in Console → Voice → TwiML Apps:

  • The Voice Request URL points at your current server. A stale URL — an old deployment, a dead ngrok tunnel from last week's dev session — makes every call fail. ngrok URLs rotate on every restart of the free tier, and this single fact is behind a remarkable share of 31000 reports.
  • The TwiML App SID in your access token matches the app you configured. If your token's outgoingApplicationSid points at a deleted or wrong app, calls die at setup.
  • The HTTP method matches what your server expects (POST by default).

Then test the webhook the way Twilio calls it, not the way your browser does:

curl -i -X POST https://your-server.com/voice \
  -d "To=+15551234567" -d "From=client:agent"

You want an HTTP 200, a Content-Type of text/xml or application/xml, and valid TwiML in the body. Anything else — a 500, an HTML error page, a redirect to a login screen, a 15-second response time — is your bug. Twilio treats webhook timeouts (15 seconds, as of August 2026) and non-TwiML responses as failures, and the browser side often reports them as 31000.

Which 31xxx error is hiding behind your 31000?

Once originalError or the Debugger surfaces a more specific code, stop debugging 31000 and fix that code. These are the ones that most often sit underneath:

Underlying codeWhat it actually meansWhere the fix lives
31201 / 31202Authorization failed — token signed with the wrong credentials (Auth Token instead of an API Key secret, wrong key SID)Rebuild the token with an API Key SID + secret
31204 / 31205Token invalid or expired — including the classic silent expiry while the tab sits idle in the backgroundCheck the TTL (1 hour by default), refresh on the SDK's tokenWillExpire event
31005The signaling WebSocket dropped mid-call and the gateway hung upWebhook failures mid-call, network interruptions
31009The SDK tried to signal before its WebSocket existedGate connect() on device state
53000Signaling never connected at allFirewall or proxy blocking wss

If no more specific code ever appears — bare 31000 with nothing underneath — the cause is almost always the TwiML/webhook layer above, or a token that expired while the page sat idle: Twilio's own engineers have confirmed on Stack Overflow that background expiry can surface as plain 31000 rather than a token code.

Stop the error-retry loop

The other genuinely-31000 failure mode is self-inflicted: an error handler that immediately retries device.register() or device.connect(). From a broken network or with an expired token, that loop hammers Twilio, floods the console with 31000s, and can crash the tab — the original Stack Overflow report of this error ends with exactly that retry-loop crash. Back off exponentially, cap retries, and after repeated failures reset the device fully (device.destroy(), then recreate) — a device stuck half-connected after 31000 often won't recover any other way. For intermittent cases tied to specific users or networks, Twilio's preflight test run from the affected network names the blocked layer in one shot.

Does 31000 happen on iOS and Android too?

Yes, and the mechanics differ enough to matter. On mobile, the classic case (documented back to the earliest SDK versions) is the OS suspending the app, the token expiring during suspension, and the SDK reporting 31000 when it wakes — after which the device object reports as online but can't receive calls. The fix is the same shape as on the web: check token validity in the SDK's stopped-listening callback, mint a fresh token, and re-initialize the device rather than reusing the stale one.

A five-minute debugging checklist

  1. Log twilioError.originalError and turn on logLevel: 1 — read what actually failed.
  2. Open Monitor → Logs → Errors in the Console — if a more specific code appears there, follow that code.
  3. curl your Voice URL with To/From form params — confirm 200, XML content type, valid TwiML, fast response.
  4. Confirm the TwiML App SID in your token matches the app whose URL you just tested.
  5. Decode the JWT — check expiry, identity, and grant contents.
  6. Reproduce on the failing network, or run Twilio's preflight test from it.
  7. Check your error handler for retry loops; destroy and recreate the Device after repeated failures.

FAQ

Is Twilio error 31000 caused by a Twilio outage? Rarely. Check status.twilio.com first to rule it out in seconds, but 31000 is almost always a configuration or network problem on the application side — a failing webhook, a stale TwiML App URL, or an expired token, in that order of likelihood.

What's the difference between error 31000 and 31005? 31005 is specific: the signaling WebSocket closed unexpectedly, usually mid-call, with the gateway sending HANGUP. 31000 is the unclassified catch-all. If you see both, debug 31005 first — it names the failing layer (the signaling connection), while 31000 only tells you something failed.

Can a Twilio trial account cause 31000? Indirectly. Trial accounts can only call verified numbers and inject a consent message into calls; a call rejected for trial-account reasons usually surfaces as 31002 Connection Declined, but layered failures sometimes degrade to 31000. Upgrading, or verifying the destination number, rules this out quickly.

How do I tell if a token caused my 31000? Timing. If the error lands roughly one TTL after page load — an hour, with Twilio's defaults — the token is your prime suspect, even though expiry normally throws its own code. Errors on the very first call of a fresh session point at configuration instead, never expiry.

Delete the four causes

Go back to the four things hiding behind 31000: TwiML App configuration, webhook uptime, token validity, reconnect behaviour. Alloqui owns all four. We provision the TwiML App and mint tokens against that same app, so the SIDs can't drift apart; we host the voice webhook, so there's no stale ngrok URL to go dead over a weekend; and the reconnect backoff is ours, so an error handler can't spin into the retry loop that crashes the tab. Paste your Twilio keys, drop in <Dialer />, and 31000 pages us instead. The free tier takes about five minutes.