Skip to main content

Knowledge > Products > Voice Agent > Troubleshooting

Voice Agent Troubleshooting

Known issues, debugging procedures, and resolution steps for the ChurchWiseAI Voice Agent.


1. Calls Not Reaching the Agent (LiveKit SIP Routing)

Symptom: Calls fail to connect — callers hear silence, a busy signal, or the Twilio default "this number is not in service" message.

Cause: The Twilio SIP trunk is not correctly configured to forward to the LiveKit Cloud SIP gateway, or the Railway agent worker is not running.

Debugging steps:

  1. Check that the Railway service is running and healthy (Railway dashboard or railway logs).
  2. Check the LiveKit Cloud project (cwa-voice-9x077mph) dashboard for active agent workers.
  3. Verify the Twilio SIP trunk is forwarding to the correct LiveKit Cloud SIP gateway URL.
  4. Check LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET are set in Railway environment variables.
  5. Check voice_call_logs — if rows exist with error_message set, the agent is receiving the call but crashing. If no rows at all, the SIP routing is failing before the agent worker.

2. Agent Worker Not Starting on Railway

Symptom: Railway deploys successfully but the agent never answers calls. Railway shows the service as running but no logs from main.py.

Debugging steps:

  1. Check Railway logs for Python import errors or missing environment variable errors at startup.
  2. Verify all required environment variables are set in Railway:
    • LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET
    • CARTESIA_API_KEY, DEEPGRAM_API_KEY
    • SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY
    • GEMINI_API_KEY, ANTHROPIC_API_KEY
  3. If the worker starts but immediately exits, check for a livekit-agents version mismatch — pin to livekit-agents~=1.5.

3. Health Check Failing on Railway

Symptom: Railway restarts the service repeatedly. Health check endpoint returns 404 or connection refused.

Cause: The FastAPI app defaults to binding to localhost (127.0.0.1), which is not accessible from Railway's health check probe. Railway needs the app to listen on 0.0.0.0.

Fix: Ensure main.py uses:

app.run(host="0.0.0.0")

The health check endpoint is:

@app.fastapi_app.get("/status")
async def health_status():
return {"status": "ok", "service": "churchwiseai-voice"}

Note: Railway uses this health check endpoint to verify the agent worker process is alive. Ensure the endpoint is present and the service binds to 0.0.0.0.


4. Calls Going to Sales Agent Instead of Church

Symptom: A church's phone number rings but the caller gets the Sales Agent instead of the church's personalized agent.

Debugging steps:

  1. Check PHONE_REGISTRY in session.py Is the church's Twilio number listed in PHONE_REGISTRY with the correct church_id?

    PHONE_REGISTRY = {
    "+1XXXXXXXXXX": "church-uuid-here",
    }

    If not listed, the system falls back to a database lookup (step 2).

  2. Check database lookup Query church_voice_agents for the phone number:

    SELECT church_id, twilio_phone_number
    FROM church_voice_agents
    WHERE twilio_phone_number = '+1XXXXXXXXXX';

    If no row exists or twilio_phone_number is null/wrong, the DB lookup returns nothing and the call falls back to Sales.

  3. Check Twilio SIP trunk forwarding Verify in the Twilio console that the church's number is forwarding to the correct LiveKit Cloud SIP gateway URL. If it is forwarding to the wrong endpoint (or not forwarding at all), calls will route incorrectly.

  4. Check call limit

    SELECT calls_this_month, calls_limit
    FROM church_voice_agents
    WHERE church_id = 'church-uuid-here';

    If calls_this_month >= calls_limit (and calls_limit > 0), the church is over its monthly limit. load_church_data() returns None and the call falls back to Sales. Reset calls_this_month to 0 if it is a new billing period.

  5. Check church_voice_agents row exists

    SELECT * FROM church_voice_agents WHERE church_id = 'church-uuid-here';

    If no row exists, the agent cannot be built and falls back to Sales.

  6. Check Railway logs Look at the INBOUND CALL log line in main.py output:

    INBOUND CALL -- to=+1XXXXXXXXXX from=+1YYYYYYYYYY room=...

    Verify the to number (from sip.trunkPhoneNumber) matches what you expect.


5. Poor Audio Quality

Symptom: Caller reports choppy audio, latency, echoing, or robotic-sounding responses.

Possible causes and fixes:

  1. Network latency The audio path is: Twilio SIP trunk → LiveKit Cloud SIP gateway → Railway agent worker → Cartesia TTS → LiveKit Cloud → Twilio. Each hop adds latency. If Railway is in a region far from LiveKit Cloud's SIP gateway, audio latency increases. Check Railway region settings and consider aligning with LiveKit Cloud's region.

  2. TTS voice selection Some Cartesia voices perform better than others in telephony contexts. The defaults are:

    • Female: Cindy (1242fb95-7ddd-44ac-8a05-9e8a22a6137d)
    • Male: Carson (86e30c1d-714b-4074-a1f2-1cb6b552fb49) Custom voices cloned from low-quality source audio may produce poor results. Verify CARTESIA_API_KEY is valid if TTS is silent.
  3. Caller's phone/network VoIP callers, poor cell signal, or speakerphone use can degrade STT accuracy, which cascades into poor responses.

  4. LLM response latency If Gemini 2.5 Flash is slow (rare), the caller hears a longer silence before the response. The filler phrases ("One moment...") mitigate this, but sustained LLM latency degrades the experience. Check Gemini API status.


6. Tools Not Executing

Symptom: The agent talks about submitting a prayer request or scheduling a callback but the tool never actually fires. No database record is created. No notification email is sent.

Debugging steps:

  1. Check feature flags in church_voice_agents

    SELECT prayer_requests_enabled, callback_scheduling_enabled,
    visitor_intake_enabled, giving_enabled, cal_enabled, pco_enabled
    FROM church_voice_agents
    WHERE church_id = 'church-uuid-here';

    Tools are only added to the agent if their corresponding feature flag is enabled. For example:

    • giving_enabled must be true AND (giving_url or etransfer_email must be set) for send_giving_link to be available
    • cal_enabled must be true AND cal_event_type_id must be set for Cal.com tools
    • pco_enabled must be true AND pco_app_id + pco_secret must be set for Planning Center tools
  2. Check the agent's tool list Look at the Railway logs for the agent build. The tools list is constructed in build_coordinator_agent() in verticals/church/agents.py. If a tool is not in the list, the LLM cannot call it.

  3. Check Supabase connectivity Tools read ctx.turn_env.supabase at runtime. If the Supabase client is None (failed to initialize), tools log a warning and return a generic success message without writing to the database.

  4. Check tool execution logs Background tools (prayer_request, callback) yield intermediate messages. Look for log lines like:

    Prayer request saved for church {church_id}
    Callback request saved for church {church_id}

    If these are missing, the DB write failed.

  5. Check notification delivery Tool notifications are fire-and-forget. Check:

    • notification_email on church_voice_agents (is it set? is it valid?)
    • notification_phone (for urgent SMS)
    • Twilio SMS logs (for SMS delivery failures)
    • Email delivery logs (Resend/SendGrid depending on current provider)

7. Wrong Theological Vocabulary

Symptom: The agent uses Protestant language for a Catholic church (e.g., "worship service" instead of "Mass") or Catholic language for a Baptist church (e.g., "parish" instead of "congregation").

Debugging steps:

  1. Check denomination in churches table

    SELECT denomination FROM churches WHERE id = 'church-uuid-here';

    The denomination field drives the theological lens selection.

  2. Check DENOMINATION_TO_LENS mapping The mapping is in core/rag.py. Verify the denomination string matches one of the keys:

    • "Catholic" or "Roman Catholic" -> lens ID 7
    • "Baptist", "Southern Baptist", etc. -> lens ID 14
    • "Methodist", "United Methodist", etc. -> lens ID 5
    • "Presbyterian", "PCA", "PCUSA", "Reformed" -> lens ID 4
    • "Non-denominational", "Community Church", "Bible Church" -> lens ID 10 (Christocentric, default)

    If the denomination string does not match any key, it falls back to Christocentric (lens ID 10).

  3. Check RAG results Session-init RAG searches unified_rag_content filtered by theological lens. If the lens is wrong, the agent receives content from the wrong tradition, which influences its vocabulary.

  4. Check the system prompt build_coordinator_prompt(church) in verticals/church/prompts.py may include denomination-specific instructions. Verify the church dict has the correct denomination value.


8. Repeat Caller History Not Loading

Symptom: The agent does not recognize a returning caller, even though the same phone has called the same church before.

Debugging steps:

  1. Check voice_call_logs for matching records

    SELECT id, from_number, church_id, summary, created_at
    FROM voice_call_logs
    WHERE from_number = '+1CALLERNUMBER'
    AND church_id = 'church-uuid-here'
    ORDER BY created_at DESC
    LIMIT 5;

    The repeat caller history looks for calls from the same from_number to the same church_id within the last 90 days.

  2. Check that summaries exist The repeat caller block only includes calls where the summary field is not null. Summaries are generated by the async Gemini classification after the call ends. If classification failed (no GEMINI_API_KEY, API error, transcript too short), the summary will be empty.

  3. Check the 90-day window

    SELECT created_at FROM voice_call_logs
    WHERE from_number = '+1CALLERNUMBER'
    AND church_id = 'church-uuid-here'
    ORDER BY created_at DESC;

    If the most recent call is older than 90 days, it will not appear in the repeat caller history.

  4. Check caller ID availability Some callers block their caller ID. If call_request.from_ is empty or anonymized, the system cannot match them to previous calls.

  5. Privacy-gated behavior Even when repeat caller history loads successfully, the agent is instructed: "Do NOT mention these unless the caller brings them up first." The history is there for context but the agent will not proactively say "I see you called last week about..."


9. SMS Not Sending

Symptom: Tools like send_sms_link, send_giving_link, or send_directions_link report failure. The caller does not receive a text message.

Debugging steps:

  1. Check Twilio credentials The SMS functions in core/notifications.py use Twilio to send SMS. Verify the environment variables:

    • TWILIO_ACCOUNT_SID
    • TWILIO_AUTH_TOKEN
    • TWILIO_PHONE_NUMBER (the "from" number for SMS)
  2. Check 10DLC registration status US carriers require 10DLC registration for A2P (application-to-person) messaging. If the Twilio number is not registered for 10DLC, messages may be silently dropped or blocked by carriers. Check the Twilio console for 10DLC campaign status.

  3. Check the "from" number The SMS must be sent from a Twilio number that is SMS-capable. Not all Twilio voice numbers support SMS. Verify in the Twilio console that the from-number has SMS capability.

  4. Check the caller's phone number

    • Is caller_phone populated? Tools fall back to ctx.turn_env.caller_phone (from caller ID) if the explicit argument is empty.
    • Is the number in E.164 format (+1XXXXXXXXXX)?
    • Is the number a landline? SMS cannot be delivered to most landlines.
  5. Check Twilio SMS logs Twilio provides detailed delivery logs in the console under Monitor > Logs > SMS. Look for error codes:

    • 30003: Unreachable destination
    • 30004: Message blocked
    • 30005: Unknown destination
    • 30006: Landline or unreachable carrier
    • 30007: Filtered (spam detection)

10. Care Agent Handoff Not Happening

Symptom: A caller shares grief, prayer needs, or emotional distress, but the Coordinator does not offer to transfer to the Care Agent. The Coordinator handles the topic directly.

Debugging steps:

  1. Check TIER_AGENTS for the church's plan

    SELECT plan FROM premium_churches WHERE church_id = 'church-uuid-here';

    Then check verticals/church/config.py:

    TIER_AGENTS = {
    "starter": ["care", "coordinator"],
    "pro": ["care", "coordinator"],
    "suite": ["care", "coordinator"],
    }

    If "care" is not in the list for the church's plan tier, the transfer_to_care tool is not added to the Coordinator and handoffs cannot happen.

  2. Check if the Care Agent built successfully The Care Agent build is wrapped in a try/except in build_coordinator_agent(). If it fails (e.g., missing ANTHROPIC_API_KEY), the system logs:

    Care Agent build failed (...), Coordinator will handle all topics

    Check Railway logs for this message.

  3. Check ANTHROPIC_API_KEY The Care Agent uses Claude Haiku 4.5 as its primary LLM. If ANTHROPIC_API_KEY is not set or is invalid, the Care Agent cannot be built.

  4. The handoff is LLM-judgment-based Unlike crisis detection (regex-based, deterministic), the Care handoff depends on the Coordinator LLM's judgment about when to transfer. The tool description instructs the LLM to "ALWAYS empathize first and ask if they'd like to speak with the Care Agent before transferring." If the LLM does not judge the conversation as requiring pastoral care, it will not offer the transfer. This is by design -- not every mention of prayer or difficulty requires a handoff.

  5. Check the Coordinator's system prompt The system prompt from build_coordinator_prompt(church) includes instructions about when to use the transfer_to_care tool. If the prompt is malformed or missing the handoff instructions, the LLM may not know the tool is available.


General Debugging Tips

Checking Railway Logs

The voice agent runs on Railway. Logs are available via the Railway dashboard or railway logs. After pushing a code change, Railway auto-deploys — monitor the deploy log for startup errors before placing a test call.

Checking Call Records

-- Recent calls for a church
SELECT call_sid, from_number, to_number, status, duration_seconds,
summary, category, urgency, created_at
FROM voice_call_logs
WHERE church_id = 'church-uuid-here'
ORDER BY created_at DESC
LIMIT 10;

Checking Church Configuration

-- Full config for a church
SELECT cva.*, c.name, c.denomination, c.address,
pc.plan, pc.calls_this_month, pc.calls_limit
FROM church_voice_agents cva
JOIN churches c ON c.id = cva.church_id
LEFT JOIN premium_churches pc ON pc.church_id = cva.church_id
WHERE cva.church_id = 'church-uuid-here';

Environment Variables Required

Set these in the Railway service environment (not in .env files):

VariableUsed ByPurpose
LIVEKIT_URLmain.pyLiveKit Cloud WebSocket URL (wss://cwa-voice-9x077mph.livekit.cloud)
LIVEKIT_API_KEYmain.pyLiveKit Cloud API key
LIVEKIT_API_SECRETmain.pyLiveKit Cloud API secret
DEEPGRAM_API_KEYmain.pySTT (Deepgram via livekit-plugins-deepgram)
CARTESIA_API_KEYagents.pyTTS (Cartesia Sonic via livekit-plugins-cartesia)
SUPABASE_URLsession.pyDatabase connection
SUPABASE_SERVICE_ROLE_KEYsession.pyDatabase auth (service role for writes)
GEMINI_API_KEYagents.py, turn_processor.pyCoordinator LLM + call classification
ANTHROPIC_API_KEYagents.pyCare Agent LLM
OPENAI_API_KEYcore/rag.pyEmbedding generation (text-embedding-3-small)
TWILIO_ACCOUNT_SIDcore/notifications.pySMS sending
TWILIO_AUTH_TOKENcore/notifications.pySMS auth
TWILIO_PHONE_NUMBERcore/notifications.pySMS from-number

If any of these are missing, the corresponding feature degrades gracefully (non-fatal) rather than crashing the call. The LiveKit variables are required for the agent to start at all.