Freeze one attempt and name the visible symptom
Record the timestamp and timezone, Asterisk linked identifier, ingress or originating extension, selecting FreePBX module and branch, saved target, Return setting, configured return destination and observed result. Classify whether the destination is absent from a selector, the call stops immediately, reaches the wrong place, loops, never returns, returns to the wrong branch or works only from one entry point.
Preserve one known-good managed destination selected by the same module when safe. Do not edit custom code, toggle Return or redirect the route before this baseline is captured; each changes a different control-flow boundary.
Prove the selector chose the exact registry entry
Start with the route, IVR, queue or other module that should select the Custom Destination. Verify its saved destination identifier and the registry row’s current description, target, Return flag and return destination. A destination that appears in a dropdown is only a registry result, while a GUI test that saves successfully is not proof that the live call selected it.
Correlate the bounded call with the generated branch and first application after selection. If the caller matched another inbound route, IVR option, timeout, invalid branch or schedule, stay at the selector rather than debugging custom code.
Prove the parsed target exists in the loaded dialplan
Expand the saved [context],[extension],[priority] into three exact values and inspect the generated destination. Then verify the owning custom source is included and the target exists in the loaded dialplan on the node that handled the call. Compare exact extensions, patterns, includes and priorities; do not infer reachability from a source filename or GUI description.
Asterisk documents that Goto changes the current context, extension and priority. If the requested location is invalid it tries the i and then h extensions where available and otherwise terminates the channel. Capture that transition instead of labeling every immediate hangup an application failure.
Separate direct transfer from the Gosub and Return stack
Current FreePBX release/17.0 source generates a direct Goto to the target when Return is disabled. When Return is enabled, it exposes a wrapper that calls the target with Gosub, logs the return point and then uses Goto for the chosen return destination. Compare the saved flag with the generated and loaded path; do not assume the description reveals the mode.
For return mode, follow every custom-code branch to an Asterisk Return and check for recursion back into the same wrapper. For direct mode, do not expect execution to resume at the selecting module. Stack errors, a missing Return, unintended fall-through or a return destination that reselects the wrapper can explain stops and loops without changing the target address.
Follow the custom application and downstream boundary
Once control reaches the target, trace the exact application result, variables and downstream destination. Keep dialplan selection separate from AGI, shell command, API, database, file, permission, trunk or endpoint failures. Capture exit status and bounded error evidence without enabling indiscriminate debug logging or placing secrets and caller data into tickets.
Review execution identity, input validation, command construction, network allowlists and calling permissions before broadening access. A command that succeeds manually as an administrator is not proof that Asterisk can execute it safely, and a downstream call attempt is not proof that the intended party answered.
Repair the smallest owner and retest both control paths
Correct only the demonstrated boundary: selector, saved target, Return flag, return destination, include, context, extension, priority, missing Return, recursion guard, application dependency or downstream route. Submit and Apply Config through FreePBX when managed state changes, then prove the generated and loaded dialplan agree; do not make a generated file the durable fix.
Retest the original success path, invalid input or application error, timeout where relevant, the configured return branch or deliberate direct transfer, loop guard and an unaffected managed destination. Preserve rollback and remove temporary logging. No PBX, custom destination, dialplan, application, security control, downstream service or call was inspected or tested for this guide.
Check for an obsolete Macro target after a FreePBX 17 restore
When the failure begins during a FreePBX 17 migration, the restored custom-macro diagnostic verifies restored files, loaded includes, unavailable Macro calls and the converted Gosub stack before changing the destination string repeatedly.
Sources & applicability
Primary references for the technical details above. Operational examples and planning checklists are VoIP.info editorial guidance.
- Sangoma Custom Destinations user guide (PBX GUI 13) ↗
- Sangoma Custom Destinations module overview (PBX GUI 13) ↗
- Sangoma Misc Applications user guide (PBX GUI 13) ↗
- FreePBX Custom Applications Registry release/17.0 metadata ↗
- FreePBX Custom Applications Registry release/17.0 dialplan source ↗
- Asterisk Goto application ↗
- Asterisk Gosub application ↗
- Asterisk Return application ↗
- Asterisk contexts, extensions and priorities ↗
- Sangoma: upgrading to FreePBX 17 ↗
- Sangoma: FreePBX 17 platform overview ↗
- Asterisk 20 Macro application reference ↗
- Asterisk Gosub subroutine guide ↗
- Asterisk LOCAL function reference ↗
- Asterisk LOCAL_PEEK function reference ↗
- Asterisk StackPop application reference ↗
Examples require adaptation to your topology. No live PBX or hardware testing is claimed.