Freeze the first unexpected transition
Record one authorized occurrence with timestamp and timezone, Asterisk branch, channel identity, loaded context, extension, priority, intended trigger, next observed priority and final channel result. Preserve whether the event was invalid input, response timeout, absolute timeout, explicit RaiseException(), an application return or hangup.
Do not begin by adding a global-looking e extension. First classify the event and the exact context executing when it occurred; the same extension number can traverse generated and custom contexts with different special handlers.
Prove that the event is an exception
If the symptom follows an application that returned unsuccessfully, inspect that application’s documented status mechanism. TryExec() returns and exposes only SUCCESS, FAILED or NOAPP through TRYSTATUS; it is a separate branch from the exception fields read by EXCEPTION().
If the design expected e, reproduce only with an actual i, t, T condition or an allow-listed RaiseException() test. Do not force production callers through invalid input or timeouts to manufacture evidence.
Inspect the current context and local special handlers
Dump or inspect the loaded dialplan for the context active at the divergence. Confirm whether e exists there and whether a local i, t or T handles the observed case first. An e in a different context does not satisfy RaiseException() in the current one.
If RaiseException() runs without a local e, Asterisk documents hangup. Treat that hangup as a missing-handler finding only after proving the raise point and loaded context, rather than inferring it from the caller’s disconnect alone.
Capture EXCEPTION fields at handler entry
At the first priority of e, capture the redacted EXCEPTION(reason), EXCEPTION(context), EXCEPTION(exten) and EXCEPTION(priority) values before calling another subroutine or raising another exception. Compare them with the frozen trace and the loaded dialplan.
A custom reason proves only the string supplied by the dialplan. An empty, unexpected or later value can reflect the wrong event, a different handler entry or overwritten evidence; it does not by itself identify the failed application.
Read TRYSTATUS before another TryExec
When TryExec() is the intended guard, record TRYSTATUS at the immediately following priority. NOAPP points to a missing or unspecified application; FAILED means a non-zero return; SUCCESS means zero. Verify the application module on the running branch and then inspect the application-specific result needed for the actual call outcome.
Do not treat SUCCESS as a completed transaction, or expect FAILED and NOAPP to invoke e. A second TryExec() can replace the value before a delayed branch reads it.
Correct one boundary and retest all exits
Add or move the handler only in the demonstrated context, remove an unintended local special extension, branch immediately on TRYSTATUS, or preserve exception fields before nested control flow. Keep cleanup idempotent and add a guard against re-entering the failing route.
Retest the demonstrated event, local i, t and T precedence where relevant, one safe custom reason, all three reachable TRYSTATUS values and an unrelated control route. Confirm the final channel treatment and remove temporary diagnostics. No PBX, module set, dialplan, channel, exception, timeout or live call was tested.
Sources & applicability
Primary references for the technical details above. Operational examples and planning checklists are VoIP.info editorial guidance.
- Asterisk special dialplan extensions ↗
- Asterisk 23 RaiseException application ↗
- Asterisk 23 EXCEPTION function ↗
- Asterisk 23 TryExec application ↗
Examples require adaptation to your topology. No live PBX or hardware testing is claimed.