DeskCaller
Craft

Why Declining a Forwarded Call Makes Your Phone Ring Again

Aneeq Iftikhar
Aneeq Iftikhar · Senior Software Engineer, DeskCaller
· 12 min read
Forwarded call decline loop cover, reading 'Decline. Ring. Repeat., the forwarded call loop', beside a glowing blue line-art mobile showing a decline X, wired to a server rack with a dashed return line looping back to the phone

The symptom is always the same. A call comes into your business number, forwards to your mobile, you press decline, and two seconds later the same phone rings again. Sometimes it loops until the caller gives up. Sometimes it does the opposite and drops the caller into your personal voicemail, greeting and all.

Both symptoms have the same cause, and it is not the one most threads on this suggest. Your PBX is not ignoring your decline. In most forwarding setups it never receives one. The signal is destroyed, reinterpreted, or made ambiguous at three separate layers between your thumb and your call routing, and once you can see all three, the fix stops being a guess.

Key takeaways

  • Pressing decline on a mobile usually does not send a rejection to your PBX at all. The mobile network treats it as a trigger for the carrier's own call forwarding, and the carrier's voicemail answers instead.
  • A voicemail answering is a 200 OK. Your PBX reads that as success, stops ringing everything else, and hands your caller to the wrong voicemail.
  • When a rejection does arrive, it is not one code. 486 Busy Here is specific to one device. 603 Decline is a global failure. Which one your handset sends is not standardised.
  • Asterisk, which is what FreePBX runs, does not read SIP response codes in its dial loop at all. It works from hangup causes, and chan_sip and chan_pjsip map them differently.
  • The fix is to stop depending on the decline signal. Set the mobile branch's ring timer below the carrier's voicemail timer, and turn on answer confirmation.

What the specs actually say about a decline

There are three plausible codes for "I do not want this call", and RFC 3261 gives them different scopes. That scope is the whole problem.

486 Busy Here is defined as end-system specific. The callee was reached, but this particular device cannot take the call, and another device registered to the same user might. 603 Decline is a 6xx, and RFC 3261 defines the entire 6xx class as global failure: definitive information about the user, not just the instance that was contacted. 480 Temporarily Unavailable covers do-not-disturb, and the spec says 486 may be used instead for a more precise reason.

So 486 means keep looking and 603 means stop looking. Same button, opposite instructions, and nothing in the spec says which one a handset must send. Cisco's own community documents that 78xx and 88xx phones return 486 on decline. Other vendors send 603.

Why the scope difference matters to a forking proxy

RFC 3261 section 16.7 is explicit about this. On receiving a 6xx, a forking proxy SHOULD cancel all pending client transactions and MUST NOT create new branches. Section 16.6 makes the same point from the other direction, defining a 2xx or 6xx final response as the thing that terminates a sequential search.

A 4xx gets none of that treatment. It fails one branch and the proxy carries on. If your failover logic sits behind a proxy and your handset sends 486, the specification is on the side of trying somewhere else, which is frequently the same person's other number.

Worth stating plainly, because it saves you chasing the wrong thing: this rule governs proxies. It does not describe what Asterisk does, and Asterisk is what a great many of these setups are actually running.

The layer that destroys the signal first

Before any of that matters, the mobile network has already had its turn.

3GPP TS 22.082, the spec for call forwarding supplementary services, defines a condition called User Determined User Busy. Pressing decline on a handset meets it, and meeting it is a defined trigger for the carrier's own call forwarding. The network does not pass your rejection upstream. It forwards the call to wherever that subscriber's forwarding is pointed, which for almost everyone is the carrier's voicemail.

That voicemail then answers. An answer is a 200 OK, which your PBX reads as success. It stops ringing every other extension, bridges the caller, and your business call is now listening to your personal voicemail greeting. FreePBX names this scenario in its own help text for Confirm Calls: a mobile phone may go to voicemail, which will pick up the call.

The race has a documented ceiling. 3GPP TS 22.082 fixes the no-reply timer between 5 and 30 seconds in 5-second steps. Vodafone UK publishes its default as 15 seconds, adjustable across that same range.

Why the same setup behaves differently for two people

Because the answer depends on which of four things is between your thumb and your routing engine, and each of them can change the outcome on its own.

Layer What it can do to a decline
The handset Send 486, or 603, or 480, or nothing at all
The mobile carrier Convert it to carrier call forwarding and answer with voicemail, 200 OK
The PBX or platform Read the code, ignore the code, or collapse everything into one status
The failover config Route "busy", "unreachable" and "no answer" to the same or different places

Two firms running the same PBX, the same trunk and the same failover rules will genuinely get different behaviour if one uses a Cisco desk phone and the other uses a Linphone client on Android. Nobody has misconfigured anything. The signal itself is underdefined.

How this looks on the platforms people actually run

FreePBX and Asterisk

Asterisk does not do what the RFC forking rules describe, because it is a back-to-back user agent rather than a proxy. Reading apps/app_dial.c, the dial loop reacts to control frames and Asterisk hangup causes, and never to SIP status codes. A failing branch is torn down and the loop continues watching the others, so a single member declining cannot end a Ring Group call.

The channel driver matters more than most people expect. Under the older chan_sip, 486, 600 and 603 all queue the same busy indication. Under chan_pjsip, which is the FreePBX 16 and 17 default, they diverge: res_pjsip maps 486 to cause 17 (User busy) and 603 to cause 21 (Call rejected). Upgrading a PBX can therefore change decline behaviour with no config change at all.

FreePBX Ring Groups have exactly one post-dial destination, Destination if no answer, and it is taken unconditionally. Decline, busy and timeout all land in the same place by design. The place FreePBX does distinguish them is the extension's Optional Destinations, whose own help text notes that a rejection counts as busy.

VoIP.ms

VoIP.ms exposes three failover branches on a DID, reachable from a Failover button on the DID edit screen: if Busy, if Unreachable, and if No Answer. All three default to None. The gate into them is the DID's Ring Time in seconds field.

Nowhere in their documentation is there a mapping from SIP response codes to those three branches. The conditions are described only in plain-English device terms, so the mapping has to be worked out from your CDRs.

There is a report of exactly the loop in question on their community forum, and it is worth reading before you configure anything. A user declining on the only registered client in a ring group found the call firing the if Unreachable branch, which was pointed at their PSTN mobile, which is the same handset. Decline, failover, ring again. Their own summary was that the server thinks a refused call counts as unreachable. No staff reply corrected it.

Twilio

Twilio collapses the distinction on purpose, and documents it. The Call resource defines no-answer as "There was no answer or the call was rejected", and error 34003 lists "The destination rejected the call. Twilio can report a rejected call as no-answer" among its causes.

So at the DialCallStatus layer that most failover logic branches on, an intentional decline and a ring-out are the same value. The discriminator exists, but it is elsewhere: SipResponseCode is delivered on StatusCallback webhooks rather than on the <Dial> action callback. If you are branching on DialCallStatus alone, you cannot tell the two apart, and no amount of tuning the timeout attribute will change that.

Hosted platforms

The hosted providers mostly do not offer a decline-versus-timeout branch at all. What the good ones offer instead is answer confirmation, which sidesteps the question.

Platform Decline vs no-answer branch Answer confirmation
RingCentral No Press 1 to accept, 2 to decline. Disableable for direct calls
Vonage Business No Screen Menu, press 1 to accept
Dialpad No Answer Forwarded Calls, cannot be fully disabled
8x8 Only on an 8x8-controlled endpoint, not a forwarded mobile Not offered for external mobiles

Dialpad's documentation makes the reasoning explicit, and warns that a 45-second ring duration loses the race against a forwarding number whose carrier voicemail answers at 30. 8x8 documents the failure mode too, noting that a connection established to an automated system counts as answered.

The fix, in three settings

Stop trying to detect the decline. The signal is unreliable by construction, and every hour spent perfecting a rule that branches on it is spent on sand.

Win the timer race

Set the mobile branch's ring timer below the carrier's voicemail timer. This is the one that fixes the wrong-voicemail symptom.

The carrier timer cannot exceed 30 seconds under 3GPP, and may be provisioned as low as 5, so a PBX ring timer of 60 seconds loses the race every time. Fifteen seconds on the PBX branch, against Vodafone UK's published 15-second default, is still too close to call. Go lower and test against the actual handset.

Turn on answer confirmation

Requiring the person to press a digit before the call bridges is the mechanism that produces a decline your system can trust, because a voicemail cannot press 1.

In FreePBX it is Confirm Calls, and it only works with the ringall strategy. Avaya ships it as Confirmed Answer, Cisco as part of Single Number Reach, and Dialpad refuses to let you switch it off at all.

Make the branches converge

Point your busy and no-answer destinations at the same sensible place, usually your own voicemail, so that when a branch does fire you do not care which one it was. On VoIP.ms that means setting all three failover tabs rather than leaving them at None.

What you should not do is add a retry. RFC 3261 permits repeating a request after a 408, which is why retry-on-failure ships enabled in so many places, and why this bug is common.

What this class of bug has in common

Every part of this is one problem wearing different hats: a phone call has no reliable way to tell you that a human decided something. Ringing, answering, rejecting and timing out are the only events available, machines can generate all four, and none of them carry intent.

You can engineer around it with confirmation digits and timer races, and you should. The ambiguity is structural rather than a bug in your particular stack.

If you are forwarding to a mobile for out-of-hours cover, the routing question underneath is worth solving properly. The 11pm burst pipe covers what a working on-call rota needs, and the answering service comparison covers what the alternatives cost.

This is also why an AI-answered line does not have the problem. There is no decline state to misread, because nothing is deciding whether to pick up. The call is answered, handled, and reaches a person when the rules say it should rather than when a timer expires. If you want that logic written down, when a voice agent should transfer to a human is the same routing question with the ambiguity removed.

Frequently asked questions

Does pressing decline send 486 or 603? Whichever your handset chooses. Both are legal. RFC 3261 defines 486 Busy Here as specific to one device and 603 Decline as a global failure covering the user, so they instruct a proxy to do opposite things. Cisco 78xx and 88xx phones send 486. On a call forwarded to a mobile you will often get neither, because the carrier converts the decline into its own call forwarding.

Why does my forwarded call go to my personal voicemail instead of the company one? Because the carrier's voicemail answered before your PBX gave up. An answer is a 200 OK, which your PBX treats as a successful connection, so it cancels the other ringing branches and bridges the caller. Shorten the PBX ring timer on the mobile branch and enable answer confirmation.

Will a shorter ring timeout alone fix the re-ring loop? It fixes the wrong-voicemail symptom, not always the loop. The loop is usually a failover branch pointing at a destination that reaches the same person, so a decline routes the call back to the handset that just declined it. Check where each of your busy, unreachable and no-answer destinations actually terminates.

Can I detect a decline in Twilio? Not from DialCallStatus, which reports a rejection as no-answer. You need SipResponseCode, which arrives on StatusCallback webhooks rather than on the <Dial> action callback, so it requires wiring up per-leg status callbacks rather than branching in your action handler.

Is this different on chan_sip versus chan_pjsip? Yes, and it catches people during upgrades. chan_sip queues the same busy indication for 486, 600 and 603. chan_pjsip maps 486 to hangup cause 17 and 603 to cause 21, so dialplan logic keyed on DIALSTATUS can behave differently after a migration you made for unrelated reasons.

🎙️ Talk to Our AI Agent

Try it now - it's live!