Capture both transactions and the exact Asterisk leg
Record the timestamp and timezone, direction, calling and called identities, dialed destination, ring duration, PJSIP channel and visible symptom. With authorization, enable pjsip set logger on only for a bounded reproduction, preserve the INVITE, provisional responses, CANCEL, 200 OK to CANCEL, 487 to INVITE and ACK, then disable protocol logging. Protect credentials, identities, telephone numbers and SDP.
Match the CANCEL to the pending INVITE by Request-URI, Call-ID, From, To, numeric CSeq and top Via branch; its CSeq method is CANCEL. A 487 is the final response to the original INVITE, not the CANCEL response. Do not infer a new call attempt from a retransmission or merge messages from different branches.
Correlate the B2BUA legs without inventing one end-to-end transaction
Asterisk terminates one SIP leg and creates another. An inbound caller can cancel the endpoint-facing leg while Asterisk sends its own CANCEL to a still-ringing phone or provider-facing branch. Channel identifiers, linked IDs, application events and precise timestamps can correlate those legs, but Call-ID, Via branch, CSeq and response ownership remain leg-specific.
Identify the element that first sent CANCEL on each leg. A phone showing 487 does not prove that the phone, Asterisk or carrier initiated the cancellation. Preserve forked called channels separately because one answered branch can cause the remaining pending branches to receive CANCEL and 487 during a successful user-visible call.
Separate translated hangup state from the wire sequence
Asterisk's hangup-cause layer is coarser than the SIP exchange and does not preserve every transaction field or cancellation owner. After Dial(), use HANGUPCAUSE_KEYS() and per-channel technology causes when several called channels existed, while retaining the wire messages as the authoritative SIP evidence. A final DIALSTATUS or CDR disposition cannot by itself distinguish caller abandonment, application timeout, losing fork branch or answer race.
Do not count every branch-level 487 as a failed business call or provider incident. First decide whether any branch answered, whether the caller had already abandoned the attempt and whether the application intentionally ended the remaining branches.
Trace the timer or application that requested cancellation
Compare the observed cancel time with the loaded Dial() timeout, queue or hunt timing, endpoint ring timeout, originate or ARI application policy and any INVITE Expires value. Asterisk's PJSIP test documentation treats caller abandonment and dial-timeout cancellation as different scenarios even though both can require an outbound CANCEL. Capture the actual application and channel state before changing a timer.
Avoid raising every timeout, disabling forking or changing NAT, codec and RTP settings merely because 487 appeared. Those changes do not identify who cancelled a pending INVITE. If the cancel originated outside Asterisk, obtain the corresponding endpoint, proxy or provider evidence rather than compensating with an unrelated local delay.
Handle the answer race and accepted dialog
A CANCEL has no effect after a final response was generated. If a 2xx answer crosses the CANCEL, the successful INVITE still requires ACK and the resulting dialog must be retained or ended with BYE. Inspect every branch for a late 2xx, ACK and BYE rather than treating the presence of one CANCEL as proof that no dialog existed. RFC 5407 provides race-condition call flows for this boundary.
When Asterisk is the caller on the affected leg, verify that its selected application or channel driver acknowledges and then clears a late accepted dialog. When Asterisk is the callee-facing server, verify the endpoint's final response and the response Asterisk produced on the other leg.
Correct one owner and retest the complete call set
Change only the demonstrated dial timeout, queue or hunt policy, application cancel rule, endpoint setting or external intermediary policy. In FreePBX, use the supported configuration owner and apply path instead of editing generated dialplan. Keep the prior value and a rollback trigger.
Retest deliberate caller abandonment, ordinary answer, no-answer timeout and every relevant forked or queue path. Confirm the expected CANCEL source and timing, both final responses, ACK handling, absence of orphaned dialogs and normal two-way media on answered calls. No PBX, endpoint, provider, proxy, timer, fork, queue or live call was tested for this guide.
Sources & applicability
Primary references for the technical details above. Operational examples and planning checklists are VoIP.info editorial guidance.
- IETF RFC 3261: CANCEL processing ↗
- IETF RFC 3261: 487 Request Terminated ↗
- IETF RFC 5407: SIP race-condition call flows ↗
- Asterisk PJSIP basic call-functionality tests ↗
- Asterisk PJSIP troubleshooting guide ↗
- Asterisk collecting debug information ↗
- Asterisk hangup cause inspection ↗
Examples require adaptation to your topology. No live PBX or hardware testing is claimed.