Troubleshooting
Trunk parks in sync_status=error#
Symptom. You created or edited a trunk, but sync_last_error is set and sip_trunk_id is null.
First check: read the error message verbatim. livekit-sip's response usually tells you the real cause.
| Carrier response | Likely cause | Fix |
|---|---|---|
401 Unauthorized |
Wrong sip_auth_username or sip_auth_password |
Verify the credentials on the carrier's portal; the value you paste is the one ScaiDial REGISTERs with |
403 Forbidden |
Source-IP whitelisting on the carrier rejects us | Send your carrier the egress IP from GET /network-info |
503 Service Unavailable |
Carrier upstream issue or our livekit-sip can't reach the address | Check sip_server_address resolves; try POST /trunks/probe to test without persisting |
408 Request Timeout |
Firewall is dropping our packets before they reach the carrier | Same as 403 — egress IP whitelisting is the usual fix |
After fixing the underlying cause, hit POST /trunks/{id}/resync — no need to recreate the trunk.
"No synced outbound trunk" on click-to-call (422)#
Symptom. The browser softphone shows "Your tenant has no synced outbound trunk."
Cause. Either no trunk exists for the tenant, or the only trunks are in sync_status="error" / "pending".
Fix. Open /scaidial/trunks and look at the sync-status badges. Either create a trunk or fix the synced one with the table above.
Calls ring but I can't hear anything#
This is almost always one of three things.
Browser mic permission denied. Open the browser's permission panel for the site. Reload after granting. The softphone publishes the mic on join — if getUserMedia fails, the room connects but no audio is sent.
Remote audio not autoplaying. Some browsers block autoplay if there hasn't been a recent user gesture. The click that originated the call counts, but if the call was initiated by a different tab or in a background context, autoplay may be blocked. Hit "Hang up" then "Place call" again, fresh.
SIP/RTP firewall. If livekit-sip can't get RTP back from the carrier, the SIP leg connects but the media path is dead. Verify your firewall lets UDP 10000-10200 (the RTP range) in and out. GET /network-info shows the exact range.
Inbound calls fail with "no_rule_matched"#
Symptom. Inbound call arrives, immediately gets end_reason=no_rule_matched.
Cause. The dialplan has no rule that matches this call. Common reasons:
- All rules use
time_windowand the call is outside the window. Add analwaysfallback rule at priority 999. - The DID isn't wired to the dialplan you edited. Check
GET /dids/{id}and verifydialplan_id. - The rule is
enabled=false.
The dialplan engine logs the rules it evaluated and why each one didn't match. Look in the ScaiGrid structured logs for scaidial_dialplan_no_match with the call ID.
Voicemail has no transcript#
Symptom. The voicemail audio plays fine but transcript and summary are null.
Cause #1. Transcripts are opt-in per tenant. Go to /scaidial/settings and enable "Voicemail transcripts." Existing voicemails won't get transcripts retroactively; new ones will from the moment you enable.
Cause #2. The opt-in is on but the transcript hasn't materialised yet. ScaiEcho runs after the recording is finalised; it's a few seconds for short messages, longer for multi-minute messages.
Cause #3. ScaiEcho returned an error (most commonly: pyannote model not loaded on the inference node, which only affects diarization — plain transcripts should still work).
Transfer fails with 409#
Symptom. Clicking Transfer surfaces "transfer failed: ..." with status 409.
Causes:
- Attended mode requested. v1 only supports blind transfer. The admin UI defaults to blind.
- Carrier rejected the REFER. Not all carriers accept SIP REFER from the answering leg. Test with
POST /trunks/probeand ask your carrier whether REFER is supported on outbound trunks. - Leg already ended. The other party hung up between when the transfer button rendered and when you clicked. The Active Calls page auto-refreshes every 4s; the window is small.
Browser softphone disconnects mid-call#
The store retries once after a transient drop. If it doesn't recover, the call card flips to error state with the disconnect reason.
If you see SERVER_SHUTDOWN, the LiveKit server (not livekit-sip — the SFU) was restarted. Calls survive controller restarts but not LiveKit-server restarts.
If you see network-level disconnects without server shutdown, check your WebRTC posture. The softphone uses LiveKit's default ICE — STUN servers + TURN if configured. If your network blocks UDP entirely, you need to configure a TCP TURN server.
"scaidial not initialized" 503#
Symptom. Per-leg control routes return 503.
Cause. The module registry constructed the ScaiDial module but its start() lifecycle hook hasn't completed yet. This is a startup window of a few seconds; it should clear by itself.
If it persists, check ScaiGrid logs for scaidial_start_failed — common causes are missing LiveKit cluster config (SCAIBOT_VOICE_LIVEKIT_URL/API_KEY/API_SECRET) or a livekit-sip sidecar that's not running. The Trunks page is still readable in this state; you just can't act on calls.
Where to look in the logs#
ScaiDial emits structured (key=value) events. The most useful keys for triage:
scaidial_inbound_dispatch_decision— every inbound INVITE, including the matched rule.scaidial_outbound_originate— every click-to-call (or other admin originate).scaidial_leg_state_change— leg state transitions; useful for figuring out where a call died.scaidial_trunk_sync_failed— the carrier's actual response, in full.scaidial_livekit_sip_*— anything wrong on the sidecar path.
Filter by correlation_id to follow a single call across components.