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.
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.
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.
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.
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 source of 31000 on outbound browser calls is the TwiML Application the call routes through. Verify three things in Console → Voice → TwiML Apps:
outgoingApplicationSid points at a deleted or wrong app, calls die at setup.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.
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 code | What it actually means | Where the fix lives |
|---|---|---|
| 31201 / 31202 | Authorization 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 / 31205 | Token invalid or expired — including the classic silent expiry while the tab sits idle in the background | Check the TTL (1 hour by default), refresh on the SDK's tokenWillExpire event |
| 31005 | The signaling WebSocket dropped mid-call and the gateway hung up | Webhook failures mid-call, network interruptions |
| 31009 | The SDK tried to signal before its WebSocket existed | Gate connect() on device state |
| 53000 | Signaling never connected at all | Firewall 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.
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.
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.
twilioError.originalError and turn on logLevel: 1 — read what actually failed.curl your Voice URL with To/From form params — confirm 200, XML content type, valid TwiML, fast response.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.
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.