Troubleshooting: in-call AI handoff, deflection, and follow-up failures
A live AI voice agent ends a call one of three ways from inside the call: it hands the caller to a human queue, it deflects the caller to SMS or WhatsApp, or it promises a follow-up message after the call ends. Each lane fails independently of the others, and each surfaces its own 500 code —HANDOFF_FAILED, DEFLECTION_FAILED, or FOLLOWUP_SEND_FAILED. Read the
code and you know which lane to work; the overall posture is the same for
all three: the failure happened inside the platform’s orchestration step,
so retry is limited and the fix is usually one configuration lookup, not a
payload change.
These codes come back from machine-to-machine endpoints the voice gateway
calls when the AI agent invokes a tool (transfer_to_human,
deflect_to_digital, or the post-call follow-up intent). The gateway is
fire-and-forget, so a 500 here never retries itself — the record of the
failure is the structured error body and the Sentry side the platform
keeps. Your customer’s live call is never dropped by any of the three:
HANDOFF_FAILED leaves the caller with the AI agent, and the two
message-send failures only lose the digital follow-up, not the call.
Code matrix — symptom to fix
Two non-500 responses sit next to these codes and are resolved on your
side, not by a retry:
Warm handoff returns 500 — HANDOFF_FAILED
POST /api/v1/internal/voice/ai-handoff is invoked by the gateway when the
live AI agent session calls the transfer_to_human tool. The
orchestration persists a context packet (call summary, sentiment, key
topics, action items, collected slots) onto the call record, bridges the
caller into the named ACD queue, and — when a conference id is supplied —
drops the bot leg once the caller is safely queued. A 500 means that
sequence broke somewhere between the packet write and the queue bridge;
the caller is still talking to the AI agent, and no handoff packet is
guaranteed.
Work it in this order:
- Confirm the queue exists and accepts entries. The most common cause is a queue id the agent names that does not resolve — deleted since the agent prompt was authored, or a typo in the tool definition. Open the queue in the dashboard (Voice → Queues) and retry the tool call. A queue at capacity rejects the same way; see Queue capacity gates.
- Check required-skills plausibility. When the agent supplies
required_skills, the queue has to hold an agent with those skills to answer; mismatched skills suspend the handoff. Either align the skills or drop them from the tool definition. - Look at the agent-runtime logs. The log line is
voice-ai-handoff: orchestration failedand it carries the underlying error message plus the call, session, and queue ids — the first thing a report needs. The dashboard status page does not expose these; pull them from your log drain or ask support for the request id. - Retry once with the same call id. The packet write and the queue enqueue are idempotent on the call, so a single retry after the queue check is safe. Persistent 500s after that are platform-side — escalate.
- Distinguish from supervisor takeovers.
SUPERVISOR_*codes on supervisor takeover failures cover a human supervisor coaching surface;HANDOFF_FAILEDis the AI bot exiting itself. The two lanes share the queue but not the codes.
transfer_to_human tool result.
Deflect-to-digital returns 500 — DEFLECTION_FAILED
POST /api/v1/internal/voice/deflect-to-digital is invoked when the agent
calls deflect_to_digital — “I’ll text you a link to finish this”. It
opens (or attaches to) a linked conversation on the target channel, stamps
the call context onto it, and sends the agent’s opening message through
the same messaging envelope any other outbound message uses. A 500 means
the send step rejected; the call continues.
Work it in this order:
- Only
smsandwhatsappare valid channels. A prompt that lets the agent promise email or voice as the deflection target breaks here — restrict the tool definition to the two enums. That is a request-side fix; retrying a 422-class reject never converges. - Resolve the sender. The message sends from the same number the
call landed on (
agent_phone, when the gateway knows it) or the org’s default sender when it isnull. A tenant with no default sender and a null agent phone fails the send — set a default sender in Settings → Channels, or ensure the DID the inbound call hits is sender- capable. See Sender resolution errors. - Content gates also count. The same messaging envelope applies the file-scan and compliance gates any outbound message applies — a link to a quarantined attachment blocks the same way it would from the inbox composer. The rejection reaches this endpoint as a 500, so check the message body against file-scan quarantine before treating it as platform-side.
- Idempotency is on (call, channel). A retry of the same deflection
for the same call and channel returns
200 already_deflectedrather than double-sending — so retry is safe, and a duplicate201is the bug to report, not the retry.
Post-call follow-up returns 500 — FOLLOWUP_SEND_FAILED
POST /api/v1/internal/conversations/post-call-followup is invoked during
voice-gateway teardown when the agent verbally promised a follow-up
(“I’ll text you”, “we’ll email you”). It picks a channel from the agent’s
promise first, the contact’s preferred channel second, and SMS as the
always-available fallback, then renders the follow-up body from the call
summary and sends it through the messaging envelope. A 500 means the send
rejected after a channel was resolved; if no channel resolved at all the
endpoint returns 204 by design, not this code.
Work it in this order:
- Read the resolved channel. The endpoint logs the channel it picked
(
sms,email, orwhatsapp) before it fails, and the 500’s lane is that channel. Work the channel-specific gate: for SMS/WhatsApp the sender-resolution and destination checks above; for email the email bounces and complaints surface. - The contact record matters. An email follow-up needs the contact’s email; when it is absent the endpoint returns 204, not a 500. A 500 on email means the address existed and the dispatch failed — check email DNS posture on email DNS drift.
- Re-trigger by resending the follow-up summary. There is no
customer-callable retry endpoint for this lane — the gateway already
tore the session down. The safe re-trigger is to send the follow-up
manually from the conversation the call opened (Inbox → pick the
caller’s thread → send), or re-queue it via the messages API with the
same summary text. The
metadata.source = voice_post_call_followuptag on the original attempt marks it on the call’s interaction record. - Idempotency is on (call). Retry of the same call id lands as
200 already_enqueued, so an accidental re-POST never double-sends — only the manual re-send steps above will.
What NOT to try
- Do not loop the retry. All three lanes are orchestration calls with bounded retry-safety (a single re-issue after configuration checks). The gateway’s fire-and-forget posture means a webhook-driven immediate re-POST turns one failure into a retry storm.
- Do not treat 204 as failure. An empty message body or a missing
destination address (email promised, none on file) short-circuits with
204 No Contentand a metric bump — that is by design. Retry only after the missing configuration is restored. - Do not confuse lanes. Supervisor-coaching failures are
SUPERVISOR_*and live on their own page. Media-path complaints after a successful handoff live on voice call quality. Neither lane belongs here. - Do not fix the caller’s experience in-place. A failed handoff keeps the caller with the AI; a failed deflection or follow-up loses only the digital message. None of the three drop the call — do not escalate these as call-quality incidents.
What to capture before escalating
Work the matching lane first. If the same code persists after the checks it names, open a ticket with:- The error code and HTTP status, verbatim (
HANDOFF_FAILED,DEFLECTION_FAILED, orFOLLOWUP_SEND_FAILED, 500). - The request ID from
meta.request_idon the failing response — the platform Sentry record is keyed to it. - The call ID and session ID off the request — either on the tool call the agent logged or from the call detail view.
- The lane-specific detail: the queue id the agent named for handoff; the channel and sender for deflection; the resolved channel and the contact’s address presence for follow-up.
- Your organization ID (Settings → Organization, or
organizationIdfromGET /api/v1/me).
See also
- Guide: hand off an AI voice call to a human —
the happy-path walkthrough for the same lane
HANDOFF_FAILEDbreaks on. - Supervisor takeover, whisper, and barge failures — the human-coaching lane that is deliberately not this page.
- Sender resolution errors — the deflection and follow-up lanes both inherit sender checks.
- Queue capacity gates — a full queue rejects a handoff the same way a missing one does.
- Error codes reference — the platform-wide catalog this page maps three codes into.