Skip to main content

Knowledge > Runbooks > Voice Ops > Voice Agent Troubleshooting Reference

Voice Agent Troubleshooting Reference

Compiled from 4+ hours of debugging on 2026-03-27, backed by 10 research agents, 5 GitHub issues, and official LiveKit/Telnyx documentation. This is the canonical reference for diagnosing and fixing voice infrastructure problems.


Known Issues and Fixes

1. Telnyx calls return "404 No trunk found" at LiveKit

Symptom: Caller hears "number not assigned" or dead air. Telnyx SIP Call Flow Tool shows INVITE sent, LiveKit returns 404 No trunk found.

Root cause: LiveKit Cloud is a shared environment where multiple Telnyx connections may share the same IP range. Without credential-based authentication, LiveKit cannot reliably match an incoming INVITE to the correct inbound trunk.

GitHub issue: livekit/sip#592 -- Telnyx FQDN credential auth causing 407/404

Fix:

  1. Telnyx side: Set user_name and password on the FQDN connection:
    curl -X PATCH "https://api.telnyx.com/v2/fqdn_connections/$CONNECTION_ID" \
    -H "Authorization: Bearer $TELNYX_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"user_name": "churchwiseai", "password": "CWA-livekit-2026!", "transport_protocol": "TCP"}'
  2. LiveKit side: Set matching auth_username and auth_password on the inbound trunk:
    /c/dev/lk.exe sip inbound update --project cwa-voice \
    --id ST_Xa3Bp9aixRFP \
    --auth-user churchwiseai \
    --auth-pass 'CWA-livekit-2026!'

Verification: Call the number. Check Telnyx SIP Call Flow Tool for 200 OK (not 404 or 407).


2. Agent never joins room (caller hears silence then "customer unavailable")

Symptom: Call connects, LiveKit creates a room, but the agent never joins. Caller hears silence for ~30s then gets disconnected with "customer unavailable."

Root cause: Dispatch rules created with deprecated top-level fields on CreateSIPDispatchRuleRequest. The room_config field (which specifies agent_name via RoomAgentDispatch) is silently ignored when using these deprecated fields. The room gets created but no agent dispatch happens.

GitHub issues:

Fix: Use SIPDispatchRuleInfo wrapper (field 10) instead of top-level fields:

# WRONG (deprecated, room_config silently ignored):
CreateSIPDispatchRuleRequest(
trunk_ids=[trunk_id],
rule=SIPDispatchRule(...),
name="...",
room_config=RoomConfiguration(agents=[...]), # IGNORED!
)

# CORRECT (use dispatch_rule wrapper):
CreateSIPDispatchRuleRequest(
dispatch_rule=SIPDispatchRuleInfo(
trunk_ids=[trunk_id],
rule=SIPDispatchRule(...),
name="...",
room_config=RoomConfiguration(
agents=[RoomAgentDispatch(agent_name="churchwiseai-voice")]
),
)
)

To update existing rules in-place (no gap):

await lk.sip.update_sip_dispatch_rule(rule_id, SIPDispatchRuleInfo(...))

Verification: lk.exe sip dispatch list -- the Agents column should show churchwiseai-voice.


3. "room is not connected" crash at startup

Symptom: Agent crashes intermittently with RuntimeError: room is not connected at wait_for_participant().

Root cause: wait_for_participant() requires an active room connection. If called before ctx.connect(), it crashes. In older code, session.start() auto-called ctx.connect(), but wait_for_participant() was placed before session.start().

GitHub issue: livekit/agents#4861 -- wait_for_participant room not connected

Fix: Call ctx.connect() explicitly before wait_for_participant():

@server.rtc_session(agent_name="churchwiseai-voice")
async def entrypoint(ctx: JobContext):
await ctx.connect() # MUST be first
participant = await ctx.wait_for_participant()
# ... rest of code

Remove any redundant ctx.connect() later in the function.


4. Explicit agent_name improves dispatch reliability

Symptom: Agent sometimes doesn't pick up dispatched calls even when dispatch rules look correct.

Root cause: Without an explicit agent_name on the @server.rtc_session() decorator, the agent relies on implicit matching which is unreliable for SIP-originated calls.

GitHub issue: livekit/agents#3202 -- Explicit agent_name fixes dispatch reliability

Fix: Always set agent_name on both sides:

  1. Decorator: @server.rtc_session(agent_name="churchwiseai-voice")
  2. Dispatch rule: RoomAgentDispatch(agent_name="churchwiseai-voice")

5. Telnyx sends phone numbers without + prefix

Symptom: Phone number lookups fail because the PHONE_REGISTRY uses E.164 format (+14144007103) but Telnyx may send 14144007103 or 4144007103.

Root cause: Telnyx SIP headers may use different number formats depending on the connection's ani_number_format and dnis_number_format settings.

Reference: Telnyx SIP Number Formats

Fix: Normalize all phone numbers immediately after extraction:

if dialed_number and not dialed_number.startswith("+"):
dialed_number = "+" + dialed_number
if caller_phone and not caller_phone.startswith("+"):
caller_phone = "+" + caller_phone

Also set ani_number_format: "+E.164" and dnis_number_format: "+e164" on the Telnyx FQDN connection.


Authentication Strategy

Primary: Credential-based auth (industry standard)

Credential-based SIP authentication is the primary strategy. This is the standard approach used by production LiveKit+Telnyx integrations at scale, including Vapi and other voice AI platforms.

How it works:

  1. Telnyx FQDN connection has user_name + password set
  2. LiveKit inbound trunk has matching auth_username + auth_password
  3. When Telnyx sends SIP INVITE, LiveKit challenges with 407 Proxy Authentication Required
  4. Telnyx responds with credentials, LiveKit matches to the correct trunk

Current credentials:

  • Username: churchwiseai
  • Password: CWA-livekit-2026!
  • Both Telnyx FQDN connection 2925081061861885519 and LiveKit trunk ST_Xa3Bp9aixRFP use these

Fallback: IP-based auth

If credential auth fails for any reason, IP-based auth via allowed_addresses on the LiveKit trunk is the fallback. However:

  • Downside: Telnyx uses shared IP ranges for FQDN connections, so IP filtering is less reliable in LiveKit Cloud's shared environment
  • When to use: Only if credential auth is confirmed broken (e.g., LiveKit Cloud bug with 407 challenges)
  • Implementation: Get Telnyx's SIP signaling IPs from their docs, add to allowed_addresses on the trunk

Sources for LiveKit+Telnyx patterns

When debugging SIP issues, check these sources for proven patterns:

  1. Vapi (vapi.ai) -- Large-scale voice AI platform using LiveKit+Telnyx. Their integration patterns are battle-tested.
  2. LiveKit Official Docs:
  3. GitHub Issues:
  4. Telnyx Support:

Operational Rules

Never delete-then-recreate trunks or dispatch rules

When updating SIP infrastructure, ALWAYS update in-place or create-then-switch-then-delete. Never delete first and create after. The gap between delete and create means incoming calls get rejected.

Safe update patterns:

  1. Trunks: Use lk.exe sip inbound update --id TRUNK_ID --auth-user X --auth-pass Y
  2. Dispatch rules (CLI): Use lk.exe sip dispatch update --id RULE_ID ... (limited fields)
  3. Dispatch rules (Python, full control): Use lk.sip.update_sip_dispatch_rule(rule_id, SIPDispatchRuleInfo(...))
  4. If you MUST recreate: Create new resource first, update references (dispatch rules pointing to trunk), verify new resource works, THEN delete old resource.

Python API method signatures (livekit-api ~1.5)

The Python API methods have different signatures than the protobuf request objects suggest:

# Dispatch rules
lk.sip.update_sip_dispatch_rule(rule_id: str, rule: SIPDispatchRuleInfo) -> SIPDispatchRuleInfo
lk.sip.update_dispatch_rule(rule_id: str, rule: SIPDispatchRuleInfo) -> SIPDispatchRuleInfo # preferred (non-deprecated)

# Inbound trunks
lk.sip.update_sip_inbound_trunk(trunk_id: str, trunk: SIPInboundTrunkInfo) -> SIPInboundTrunkInfo

# Import paths
from livekit.protocol.room import RoomConfiguration
from livekit.protocol.agent_dispatch import RoomAgentDispatch # NOT from room!
from livekit.protocol.sip import SIPDispatchRuleInfo, SIPDispatchRule, SIPDispatchRuleIndividual

Verify after every change

After any SIP infrastructure change:

  1. lk.exe sip dispatch list -- check Agents column is populated
  2. lk.exe sip inbound list -- check Authentication column shows credentials
  3. lk.exe agent list -- check agent is deployed and version is current
  4. Make a test call to verify end-to-end

Current Infrastructure (as of 2026-03-28)

ComponentIDDetails
AgentCA_pX3Me4NK6qK8Region: us-east, agent_name: churchwiseai-voice
Main trunkST_Xa3Bp9aixRFP4 numbers, credential auth (churchwiseai)
Test trunkST_hvf5m2RXfEiS+13658253552, no auth (internal testing)
Main dispatchSDR_cYzx7sAkUTvxroom_prefix="call-", agent=churchwiseai-voice
Test dispatchSDR_Wpyno7GDNQqgroom_prefix="test-call-", agent=churchwiseai-voice
Telnyx FQDN2925081061861885519LiveKit ChurchWiseAI, TCP, credential auth
Telnyx FQDN record29250833494185102075u9xu5ysoly.sip.livekit.cloud:5060

GitHub Issues Reference

IssueSummaryStatus
livekit/sip#592Telnyx FQDN credential auth 407/404 in shared envWorkaround: credential auth
livekit/sip#401Named agent dispatch broken with deprecated fieldsFixed: use SIPDispatchRuleInfo wrapper
livekit/livekit#3690room_config silently ignored on deprecated pathFixed: use dispatch_rule field 10
livekit/agents#3202Explicit agent_name fixes dispatch reliabilityFixed: agent_name on decorator + dispatch
livekit/agents#4861wait_for_participant room not connectedFixed: ctx.connect() before wait_for_participant

Official Docs Reference

TopicURL
LiveKit Telnyx Setup Guidehttps://docs.livekit.io/sip/quickstarts/configuring-telnyx-trunk/
LiveKit SIP Lifecycle Recipehttps://docs.livekit.io/recipes/sip_lifecycle/
Telnyx SIP Number Formatshttps://support.telnyx.com/en/articles/1130706-sip-connection-number-formats
LiveKit SIP Trunking Docshttps://docs.livekit.io/sip/
LiveKit Agent Deploymenthttps://docs.livekit.io/agents/deployment/
LiveKit Multi-Agent Docshttps://docs.livekit.io/agents/build/multiagent/