Dial()

"No devices or endpoints to dial" in Asterisk

This one has a nasty property: the line that fails is not the line with the bug. Dial() ran with nothing to dial because a variable was empty, and Asterisk logs no warning at the point where the variable was set.

What it looks like in the log

[2026-08-17 10:58:12] VERBOSE[6620][C-00000ff1] pbx.c: Executing [s@outbound:8] Dial("PJSIP/1002-000012f4", "PJSIP/@trunk-main,30") in new stack
[2026-08-17 10:58:12] VERBOSE[6620][C-00000ff1] app_dial.c: No devices or endpoints to dial

What it means

Look closely at the dial string in the log line: PJSIP/@trunk-main. There is nothing between the slash and the at sign. A variable that was supposed to hold the number resolved to an empty string, and Asterisk cheerfully built a dial string around the nothing it was given.

The reason this is hard to find is that setting a variable to an empty value is completely legal in Asterisk and produces no warning at all. The first visible symptom appears here, one or more steps after the actual mistake, and pointing at the wrong line.

Most common causes

  1. 01A database or ODBC lookup that returned no rows

    The subtle case. A lookup that fails outright usually logs something. A lookup that succeeds and returns zero rows sets the variable to empty and logs nothing, and that empty value flows downstream looking exactly like this.

  2. 02An AGI script that did not set the variable

    A script that exits early, hits an unhandled branch, or writes to the wrong variable name leaves the expected one unset.

  3. 03A misspelled variable name

    Referencing ${DEST} where the value was stored in ${DESTINATION} yields an empty string silently. There is no undefined-variable error to catch this.

  4. 04A header or channel variable that was not present

    Reading a SIP header that this particular call did not carry gives an empty result, so the failure appears only on the subset of calls missing that header.

  5. 05A pattern match that captured nothing

    A dialplan pattern whose capture group did not match produces an empty substitution rather than failing the match.

How to tell which one it is

The dial string in the log tells you exactly which part of it was empty by its shape. PJSIP/@trunk means the number was empty. PJSIP/12025550143@ means the trunk name was. /1234 with no technology means the tech variable was.

From there, trace backwards through this call's dialplan execution to the Set(), AGI() or function call that was supposed to populate it. The value is not visible in the log, but the step that should have produced it is, and checking whether that step ran at all usually answers the question.

How to fix it

Related failures