Skip to main content

Call-Setup Failures

A call-setup failure is any attempt that never reaches the talking state: the caller hears a fast busy or a SIP error, an outbound leg returns immediately, or an originate from the console comes back with an error. Almost every one of these leaves a single, decisive piece of evidence behind — a hangup cause — and the fastest path to a fix is to read that cause first and only then look at where it came from.

This chapter is diagnostic. It assumes you can already place a call and watch the console; it does not re-explain dialplan or gateway configuration. For the configuration side, see the Dialplan Application Reference, the Inbound Public Context chapter, Gateways, and the Channel Variables reference.

Reading a hangup cause

FreeSWITCH terminates every channel with a Q.850 call cause. The cause is exposed three ways, all of which carry the same uppercase name:

  • The channel variable hangup_cause, available in the dialplan, in events, and in the CDR.
  • The Hangup-Cause header on the CHANNEL_HANGUP event.
  • The log line printed when the channel hangs up.

The names come from a fixed table in the core (CAUSE_CHART in src/switch_channel.c), and switch_channel_cause2str() is what turns the numeric cause into the string you see. The most common call-setup causes are:

CauseQ.850What it means at setup time
NORMAL_CLEARING16The call ended cleanly. At setup this usually means the far end answered then hung up, or a 200 OK was followed by a normal teardown.
USER_BUSY17Destination is busy — a SIP 486 or 600, or a registered endpoint returning busy.
NO_USER_RESPONSE18No response from the destination within the protocol timer; maps from SIP 480.
NO_ANSWER19The destination rang but no one answered before the timeout.
SUBSCRIBER_ABSENT20The user exists but is currently unreachable.
CALL_REJECTED21The far end actively refused — SIP 401, 402, 403, 407, 603, or 608.
NUMBER_CHANGED22SIP 410 Gone.
INVALID_NUMBER_FORMAT28The dialed number was malformed for the route; SIP 484 Address Incomplete.
NORMAL_TEMPORARY_FAILURE41A transient upstream failure — SIP 400, 481, 500, or 503. Retry-worthy.
NETWORK_OUT_OF_ORDER38SIP 502 Bad Gateway.
SERVICE_UNAVAILABLE63Service not available on this route; SIP 405.
INCOMPATIBLE_DESTINATION88Codec or media negotiation failed; SIP 488 or 606.
RECOVERY_ON_TIMER_EXPIRE102A timer expired with no answer at all; SIP 408 Request Timeout or 504.
UNALLOCATED_NUMBER1The number is not assigned; SIP 404 Not Found.
NO_ROUTE_DESTINATION3No route to the destination; SIP 485 Ambiguous or 604.

The non-Q.850 causes FreeSWITCH adds for its own conditions are equally useful at setup time:

CauseWhat it means
USER_NOT_REGISTEREDYou tried to reach a user/ or registered endpoint that has no live registration.
GATEWAY_DOWNThe named gateway exists but is not usable (not registered, or marked down).
INVALID_GATEWAYThe gateway name in the dial string does not exist.
INVALID_URLThe dial string could not be parsed into a valid URL.
INVALID_PROFILEThe Sofia profile named in the dial string does not exist or is not running.
ORIGINATOR_CANCELThe originator (A-leg or the originate caller) cancelled before answer; SIP 487.
PROGRESS_TIMEOUTThe call got media/progress but never advanced; controlled by the progress timeout.
ALLOTTED_TIMEOUTThe originate-wide timeout elapsed before any leg answered.
tip

Two extra variables sharpen the picture for SIP legs. sip_term_status holds the bare SIP response number (for example 480), and proto_specific_hangup_cause holds it as sip:480. Both are set from the actual response code before it is folded into the Q.850 cause, so they tell you the wire reason even when several SIP codes collapse to one cause. On a bridge, the B-leg's cause is copied to the A-leg as last_bridge_hangup_cause, and originate_disposition records the outcome of an originate (success, failure, or the cause string itself).

Symptom: the call never matched an extension

Symptom. The call arrives but nothing happens, or it is rejected outright, and no dialplan action you expected runs.

Cause. The destination number, context, or dialplan name FreeSWITCH used does not match the extension you wrote. The single most common version is an inbound call landing in the wrong context — calls from an unauthenticated source arrive in public, not default.

Confirm. Raise the console to at least INFO and place the call. The XML dialplan prints exactly what it is routing, from mod_dialplan_xml:

Processing Caller Name <1001>->18005551212 in context public

That one line gives you the caller-ID name, the caller-ID number, the destination number it will try to match, and the context it is matching in. If the context reads public when you expected default, the call came in unauthenticated and is being handled by your public dialplan — which by design should not reach your internal extensions. Raise the verbosity further with console loglevel debug to see each condition evaluated:

Dialplan: Processing recursive conditions level:0 ...
Dialplan: sofia/internal/... Regex (FAIL) [my_ext] destination_number(18005551212) =~ /^(1\d{10})$/ match=false
Dialplan: sofia/internal/... Action set(...)

Regex (PASS) / Regex (FAIL) shows precisely which condition matched and which did not, so you can see whether the problem is your pattern or the destination number itself.

Fix. Match the context, dialplan name, and destination shown in the Processing ... line against your XML. If the context is public, decide whether the call should be authenticated (fix the source so it registers or falls inside your ACL) or whether the public context should explicitly route it into default with a transfer. The Inbound Public Context chapter covers that handoff; the conditions and the transfer application are documented in the Dialplan Application Reference.

Symptom: outbound call fails through a gateway

Symptom. Calls to an external number fail instantly with GATEWAY_DOWN, USER_NOT_REGISTERED, or NORMAL_TEMPORARY_FAILURE, and the B-leg never even sends an INVITE you can trace.

Cause. The gateway is not in a usable state. A gateway you expect to be registered may be retrying, failed, or expired.

Confirm. Ask Sofia directly:

sofia status gateway my_gateway

The output has two state fields that you must read together. The State line is the registration state machine, and the Status line is the up/down summary:

State REGED
Status UP

State is one of the values from sofia_state_names in mod_sofia.c:

StateMeaning
REGEDRegistered and current — the healthy state for a registering gateway.
TRYINGA REGISTER is in flight.
REGISTERQueued to send a REGISTER.
UNREGEDNot registered (the starting / reset state).
UNREGISTERQueued to send an un-REGISTER.
FAILEDThe last REGISTER attempt failed.
FAIL_WAITBacking off after a failure before retrying.
EXPIREDThe registration lapsed and has not yet been renewed.
NOREGConfigured not to register (register=false) — normal for IP-auth trunks.
DOWNThe gateway is down / unregistered.
TIMEOUTThe REGISTER timed out with no response.

Status is simpler — it is only ever DOWN or UP (with a trailing (ping) when an OPTIONS ping is in flight), from the status_names table in mod_sofia.c.

The combinations that explain a failed outbound call:

  • State NOREG / Status UP — an IP-authenticated trunk that does not register. This is healthy; the problem is elsewhere (dialplan, codecs, or the upstream).
  • State NOREG / Status DOWN — a non-registering gateway whose OPTIONS ping is failing; the far end is unreachable.
  • State FAILED, FAIL_WAIT, EXPIRED, or TIMEOUT — registration is broken. This is a credentials, network, or far-end problem, and any call routed through it returns GATEWAY_DOWN.

Fix. Bring the gateway back to a usable state. For a registering gateway, correct the credentials or realm and re-register; for a non-registering trunk, fix the network path or the ping target. Gateway parameters and the OPTIONS-ping keepalive are covered in Gateways.

Symptom: upstream returns 403, 404, 480, or 503

Symptom. A SIP trace shows the far end answering your INVITE with an error response, and the leg ends with a Q.850 cause rather than the raw SIP number.

Cause. mod_sofia maps every final SIP response onto a Q.850 cause (sofia_glue_sip_cause_to_freeswitch in sofia_glue.c). Several SIP codes can collapse onto one cause, which is why the cause alone can be ambiguous — read the SIP code too.

Confirm. Turn on SIP tracing for the profile and re-run the call:

sofia profile internal siptrace on

(or sofia global siptrace on for every profile). Then read the response code in the trace and check proto_specific_hangup_cause / sip_term_status on the leg. The mappings you will hit most:

SIP responseMaps to cause
403 Forbidden (also 401, 402, 407, 603, 608)CALL_REJECTED
404 Not FoundUNALLOCATED_NUMBER
480 Temporarily UnavailableNO_USER_RESPONSE
486 Busy Here (also 600)USER_BUSY
484 Address IncompleteINVALID_NUMBER_FORMAT
488 Not Acceptable Here (also 606)INCOMPATIBLE_DESTINATION
408 / 504RECOVERY_ON_TIMER_EXPIRE
485 / 604NO_ROUTE_DESTINATION
502 Bad GatewayNETWORK_OUT_OF_ORDER
400 / 481 / 500 / 503NORMAL_TEMPORARY_FAILURE
487 Request TerminatedORIGINATOR_CANCEL

Note the non-obvious ones: a 404 becomes UNALLOCATED_NUMBER (not NO_ROUTE_DESTINATION), and a 480 becomes NO_USER_RESPONSE (not NO_ANSWER). Any SIP code with no explicit mapping falls through to NORMAL_UNSPECIFIED.

Fix. The fix lives upstream, not in FreeSWITCH: a 403 is the provider rejecting your credentials or caller-ID, a 404 is a number the provider does not recognize, a 480/503 is the destination temporarily down. Correct the outbound identity or route and retry.

Symptom: a bridge ends instead of trying the next leg

Symptom. A bridge to multiple destinations stops at the first failure, or conversely keeps going when you wanted it to stop, and the dialplan continues (or hangs up) unexpectedly.

Cause. Whether the dialplan continues after a failed outbound leg is governed by continue_on_fail and failure_causes (read in switch_channel.c). By default, with neither variable set, only NO_ANSWER, NO_USER_RESPONSE, and ORIGINATOR_CANCEL are treated as "keep going" — every other cause hangs up the A-leg.

Confirm. Inspect the cause of the failed B-leg (hangup_cause, or last_bridge_hangup_cause on the A-leg) and check which variables are set:

  • continue_on_fail=true — continue the dialplan on any failure cause.
  • continue_on_fail=false — do not continue (only the listed causes, if any, let it through).
  • continue_on_fail=user_busy,no_route_destination,603 — continue only when the cause matches one of these names or numbers (case-insensitive; numeric Q.850 values are accepted).
  • failure_causes=... — the inverse filter: only the listed causes are treated as failures that stop processing; everything else continues.

ATTENDED_TRANSFER is always treated as a non-failure and never triggers continuation logic.

For parallel originate (the , and | operators), fail_on_single_reject controls whether one rejected leg aborts the whole set. Set fail_on_single_reject=true to abort on the first reject, or give it a comma-list of causes to abort only on those; prefix with ! to invert. Use originate_continue_on_timeout to keep trying remaining legs after the timeout.

Fix. Set continue_on_fail (or failure_causes) to match the routing you want before the bridge. These are ordinary channel variables — see Channel Variables — and the bridge application is in the Dialplan Application Reference.

Symptom: originate from the CLI returns -ERR

Symptom. You run originate from fs_cli and it returns an error rather than connecting.

Cause. The originate API command reports its result directly. On success it prints the new session UUID; on failure it prints the Q.850 cause of the failed attempt (from originate_function in mod_commands.c).

Confirm. Read the response:

freeswitch@host> originate sofia/gateway/my_gateway/18005551212 &echo
-ERR GATEWAY_DOWN

A success looks like:

+OK 4f8c9a10-...-uuid

The string after -ERR is exactly the cause name from the table above, so the same reasoning applies: -ERR USER_NOT_REGISTERED means the destination has no live registration, -ERR INVALID_GATEWAY means the gateway name is wrong, -ERR NO_ROUTE_DESTINATION means there was no usable route, and -ERR RECOVERY_ON_TIMER_EXPIRE means it timed out with no response.

Fix. Map the -ERR cause back to its section above and fix the underlying condition — the gateway state, the registration, the dial string, or the upstream. Re-run the same originate with sofia profile <name> siptrace on if the cause points at the SIP exchange and you need to see the wire response.