Back to Insights
Technology

Why Voice Agent Calls Fail: Reading the SIP Logs

A dashboard that says 'error' tells you nothing. The four layers a phone call fails at, the SIP response codes and Q.850 causes that name the cause, and a triage order that converges instead of guessing.

J

Jesper Rietbergen

CEO/CTO, VoiceDock

Published July 30, 2026
13 min read

A caller says they phoned and it did not work. Your dashboard says the call ended with an error. Those two sentences are the whole problem: somewhere between the caller's handset and your agent, seven things could have gone wrong, and a single word in a dashboard cannot tell you which. The answer is almost always sitting in the SIP dialog, one layer below where most voice-AI platforms let you look.

Four layers, and only one of them is the AI

When people debug a voice agent they reach for the prompt first, because that is the part they wrote. But a phone call is a stack, and the model sits near the top of it. Below the agent there is an orchestration layer that decides which assistant answers and holds the session. Below that is SIP, the signalling protocol that sets the call up, negotiates what audio both sides can speak, and tears it down again. And below that, running on its own separate path, is the media: the actual RTP packets carrying voice.

That last split is the single most useful thing to internalise. Signalling and media travel separately. A call can be perfectly connected at the SIP layer while no audio flows at all, which is why "the call connected but the agent never spoke" is a media problem and not a prompting problem. Ninety percent of the confusion in voice AI debugging comes from treating one stack as if it were the other.

The rule

Fix the layer the symptom lives in

Caller hears nothing at all: media. Call is refused instantly: signalling. Agent answers but says the wrong thing: model. Agent answers, then goes quiet mid-sentence: usually neither, it is the session. Guessing across layers is how a fifteen-minute fix becomes a two-day one.

What a healthy call looks like in SIP

Before you can spot a broken dialog you need to know what an intact one reads like. An inbound call is a short, extremely predictable conversation between the carrier and your platform. The carrier offers the call with an INVITE that includes an SDP body listing the codecs it can speak. Your side acknowledges, rings, answers with 200 OK and its own SDP, and both ends start sending RTP. When someone hangs up, a BYE closes it with a reason.

inbound-call.sip.log
>> INVITE sip:+31570238200@trunk SIP/2.0
   From: <sip:+31612345678@carrier>;tag=8f2b
   Call-ID: 4c1d9e77-3a2f-4b10-9c8e-11e2a6d0f5aa
   SDP: audio 41002 RTP/AVP 8 0 101   (PCMA, PCMU, telephone-event)

<< SIP/2.0 100 Trying
<< SIP/2.0 180 Ringing
<< SIP/2.0 200 OK
   SDP: audio 24518 RTP/AVP 8 101     (PCMA agreed)

   [rtp] inbound  stream established   ssrc=0x6b21f0
   [rtp] outbound stream established   ssrc=0x11c4ae

>> BYE sip:+31570238200@trunk SIP/2.0
   Reason: Q.850;cause=16;text="normal clearing"

   call ended · 47.2s · two-way audio · caller hung up

Four things in that trace are worth pointing at. The Call-ID is the handle that ties every packet, log line and recording of this one call together, and it is the first thing to ask for when a customer reports a problem. The SDP lines show a codec negotiation that succeeded: the carrier offered PCMA, PCMU and telephone-event, and your side agreed on PCMA. The two RTP lines confirm audio in both directions, each with its own synchronisation source. And the BYE carries a Q.850 cause, which is the telephony network telling you in a standard number why the call ended.

The response codes that explain a failure

When a call does not survive setup, the SIP response code is the diagnosis. Most voice platforms collapse all of these into "failed", which throws away the only information that would have told you whose problem it is. These are the ones that actually show up on live trunks.

CodeMeansWho owns it
403 ForbiddenThe trunk rejected the request outright, usually an IP that is not on the allow-list, or credentials that do not match.Configuration
404 Not FoundThe number does not exist on that trunk. Frequently a routing entry that was never created, or a number ported away.Carrier / routing
407 Proxy Authentication RequiredRegistration or digest auth is not completing. Normal as a first challenge; a problem when it repeats.Configuration
408 Request TimeoutNobody answered the signalling at all. Often a firewall silently dropping SIP, not a busy line.Network
480 Temporarily UnavailableReached the right place, but no endpoint was available to take it. On an AI trunk this often means no worker picked up the session.Platform
486 Busy HereA real busy signal, or a concurrency ceiling being hit. Worth checking your own limits before blaming the carrier.Platform / capacity
487 Request TerminatedThe call was cancelled before it was answered: the caller hung up during ringing. Not a fault.Nobody
488 Not Acceptable HereCodec or SDP mismatch. Both sides were willing to talk and could not agree on how. Silent, instant, and never the model's fault.Configuration
503 Service UnavailableThe far end is up but declining work: congestion, a carrier incident, or a downstream component refusing.Carrier / platform
Codes as defined in RFC 3261 and its extensions. The 'who owns it' column is our own triage shorthand, not part of the standard.

The 488 deserves its own paragraph, because it is the failure that looks most like magic. Here the same call, offered with a codec the trunk was not configured to accept:

codec-mismatch.sip.log
>> INVITE sip:+31570238200@trunk SIP/2.0
   SDP: audio 41002 RTP/AVP 9 101     (G.722, telephone-event)

<< SIP/2.0 100 Trying
<< SIP/2.0 488 Not Acceptable Here
   Warning: 304 "Media type not available"

   call never connected · 0.4s · no RTP · no transcript

Four hundred milliseconds, no audio, no transcript, nothing for the model to have done wrong. From a dashboard that only reports end reasons this is indistinguishable from a dozen other failures. From the SIP dialog it is a five-minute fix in the trunk's codec list.

One code deserves a mention precisely because it never appears in a failure: OPTIONS. It is not an error at all, it is a keepalive: a small periodic request whose only job is to ask the other end whether it is still there. Enabling OPTIONS pings on a trunk, at an interval in the region of thirty seconds, turns "is the trunk alive" from a question you answer during an incident into a graph you can look at before one. It also keeps NAT bindings warm, which quietly prevents a class of one-way audio failures described below. It is the cheapest monitoring in telephony and it is switched off by default nearly everywhere.

Q.850 cause codes worth memorising

Where SIP describes the request, Q.850 describes what the telephone network thought of it. Cause codes arrive in the Reason header on a BYE or a CANCEL, and they survive across gateways, so they often carry the truth even when the SIP code has been rewritten somewhere along the path.

CauseStandard meaningWhat it usually is in practice
1Unallocated numberThe dialled number is not assigned. On outbound campaigns this is a bad data problem, not a platform problem.
16Normal clearingA healthy hang-up. Seeing this on a call the customer says failed means the failure was in the audio, not the call.
17User busyGenuinely engaged, or a device rejecting a second call.
19No answer from userIt rang out. Check your ring timeout before assuming the number is dead.
21Call rejectedSomething actively said no: a blocklist, a spam filter, or a carrier policy on the destination.
34No circuit availableCapacity, upstream. Retry logic matters here; a hard fail does not.
38Network out of orderA real upstream fault. This is the one where you check the carrier's status page first.
41Temporary failureThe vaguest useful code. Almost always worth one retry.
102Recovery on timer expirySomething did not answer in time and a timer gave up. Points at latency or a stalled leg, not at a rejection.
127Interworking, unspecifiedA gateway translated something and lost the original reason. Treat as 'no information available'.
Cause values from ITU-T Q.850. The right-hand column is our field reading, not the standard.

One-way audio: the classic that is never the model

The most common serious complaint on any new voice deployment is that one side cannot hear the other. The caller hears the agent perfectly and the agent behaves as if the caller never spoke, or the reverse. It presents as an AI failure and it is almost never an AI failure.

Because media travels on its own path, audio only works if RTP can reach both endpoints in both directions. Signalling can complete over one route while the media route is blocked, and nothing in the SIP dialog will complain. The usual culprits are predictable: a firewall permitting the SIP port but not the RTP range, network address translation rewriting an address inside the SDP so the far end sends packets into nowhere, or symmetric-RTP expectations that one side does not honour.

The diagnosis is mechanical rather than clever. Look at the packet counters for each direction separately. If inbound RTP is arriving and outbound is zero, you have a routing or filtering problem on the way out, not a transcription problem. If both counters are healthy and the agent still behaves as if it heard silence, only then does it become a speech-recognition question.

Why this matters commercially

This is the layer a reseller cannot reach

If your voice vendor is a wrapper around someone else's platform, this whole section is outside their reach. They can read a status field and open a support ticket. They cannot look at RTP counters on the trunk, because the trunk is not theirs. On a phone line that a business depends on, that difference decides whether an outage lasts twenty minutes or three days.

When the keypress does not register

A caller is asked to press 1 and presses 1, and nothing happens. DTMF, the tones a keypad makes, can travel in three different ways, and a mismatch between them is silent. The tone can be carried as its own RTP payload type as described in RFC 4733 and its predecessor RFC 2833, which is what the telephone-event entry in the SDP above is announcing. It can be sent as plain audio, mixed into the voice stream, which survives fewer hops than people expect. Or it can be sent out-of-band as a SIP INFO message, entirely outside the media path.

If your side is listening for RTP events and the carrier is sending inband tones, the keypress is physically present in the audio and completely invisible to your application. Confirm which of the three is actually in use before touching anything in the agent, and prefer negotiating telephone-event in the SDP so the tone arrives as a discrete event rather than as a sound you have to detect.

Why your end reason is not a diagnosis

Good platforms give you a deterministic end reason per call. On VoiceDock every call closes with one of a fixed set: the caller hung up, the assistant hung up, the call was transferred, it hit its maximum duration, voicemail was detected, nobody answered, credit ran out, or an error occurred. That set is genuinely useful for reporting, because it means you can count outcomes without parsing free text.

What an end reason cannot do is explain a failure. "Error" is a category, not a cause. The value of owning the layer underneath is that when the category is not enough, there is a next question to ask: which SIP code, which Q.850 cause, which direction was the RTP missing in, which Call-ID. A platform that stops at the end reason has made that next question unanswerable by design.

The end reason tells you what happened to the call. The SIP dialog tells you why. You need a vendor who can hand you both.

A triage order that actually converges

Debugging telephony badly means opening five things at once. Debugging it well means asking questions in an order that halves the search space each time. This is the order we use.

  1. 01

    Get the Call-ID before anything else

    Everything else is guesswork without it. A timestamp and a caller number will do if that is all the customer has, but the Call-ID turns a story into a record.
  2. 02

    Establish whether the call connected at all

    A 200 OK splits the problem cleanly. No 200 OK means the failure is in setup and the response code names it. A 200 OK means setup worked and you move to media.
  3. 03

    Check RTP in each direction separately

    Two counters, not one. Silence in one direction only is a network or NAT problem, and it is the single most likely cause of "the agent ignored me".
  4. 04

    Read the closing cause, not just the status

    A Q.850 cause of 16 on a call the customer says failed is a strong signal: the call was fine and the experience was not. That points at audio quality, latency, or the agent, and away from telephony.
  5. 05

    Only now open the transcript and the prompt

    If setup succeeded, audio flowed both ways and the call closed normally, then and only then is it a model or instruction problem, and you have ruled out four layers of noise before spending time there.

None of this is exotic knowledge. It is ordinary telephony engineering, and it is exactly what disappears when a voice platform treats the phone network as an implementation detail you are not allowed to see. We publish it because the question is not whether calls will occasionally fail on a real network. They will. The question is whether the people you build with can tell you why.

Sources Response codes and dialog behaviour as defined in RFC 3261 (SIP), DTMF carriage in RFC 4733, and cause values from ITU-T Q.850. The triage order and the practical readings reflect our own experience running voice traffic on production trunks.