Skip to main content

Troubleshooting: voice agent dispatch eligibility

A voice call that reaches an ACD queue can still fail to place an agent on the line. The operator-visible refusal falls into one of three codes, and each one points to a different layer of the dispatch gate. This page maps VOICE_AGENT_MISSING, VOICE_AGENT_UNAVAILABLE, and VOICE_OPERATOR_LIMIT_EXCEEDED to the control you own and the fastest path back to ringing agents. These codes surface when the queue dispatcher has already accepted the call and is now trying to attach an agent. They are not destination blocks, call-quality failures, or handoff errors. Read the code first, then work the matching section below.

Distinguish the three dispatch refusals

VOICE_AGENT_MISSING is a data-lookup failure: the queue’s routing logic nominated an agent id that is not present. VOICE_AGENT_UNAVAILABLE is an eligibility failure: the agent is real but is currently busy, wrapup, paused, offline, or not a member of the queue, or their skills do not cover the queue entry’s requirements. VOICE_OPERATOR_LIMIT_EXCEEDED is a concurrency cap: the agent was eligible, but the tenant-wide simultaneous-operator ceiling rejected the join attempt.

Diagnose per code

VOICE_AGENT_MISSING — no agent row

  1. Find the agent id the queue resolved. The refusal body includes the agent id the dispatcher tried to claim. Copy it before anything else.
  2. Check whether the id exists. Open the agent in the dashboard (Voice → Agents, or GET /api/v1/voice/agents/{id}). If the id returns 404, the row was deleted, the id was renamed, or the queue config is pointing at a stale reference.
  3. Trace where the id came from. Queue membership lists, routing-rule fallback user ids, and supervisor reassignment targets can all nominate an agent id. The most common cause is a deleted agent left behind in one of those lists.
  4. Fix by removing or replacing the stale reference. Either re-add the agent under a new id and update every membership, or remove the stale id from the queue / routing rule so dispatch no longer resolves it.

VOICE_AGENT_UNAVAILABLE — agent row exists but membership does not pass the gate

  1. Read the agent’s worst-case state across all queues. Presence is stored per queue membership, and every dispatch reader folds memberships into one worst-case state by severity: busy > wrapup > paused > offline > available. An agent who is available on one queue but paused on another is treated as paused for voice claim purposes. See Agent presence and aux-code lifecycle.
  2. Check queue membership. Confirm the agent is a member of the queue the call entered. GET /api/v1/voice/queues/{id}/members lists members; if the agent is absent, add them or fix the routing rule that sent the call to the wrong queue.
  3. Check the per-call skills filter. The queue entry may carry requiredSkills. If the agent’s skillLevels do not intersect, dispatch skips them even when they are available. Read the routing-decision audit (GET /api/v1/inbox/routing-decisions/{conversationId} or the queue decision log) to see the skills-filter reason.
  4. Check wrap-up and aux-code drift. An agent stuck in wrapup after a call ended, or stuck in paused after a reason-code overrun, looks eligible in the directory but is not. Use POST /api/v1/voice/agents/{id}/status to force the correct state, or wait for the wrap-up timer / overrun scheduler to clear it.

VOICE_OPERATOR_LIMIT_EXCEEDED — operator ceiling tripped

  1. Read the limit in the refusal. The error body includes the ceiling value and the current count, for example { "limit": 50, "current": 50 }.
  2. Distinguish a real spike from a leak. A short spike during a campaign burst or a simultaneous shift change is expected. A count that stays pinned at the ceiling between calls suggests agents are not being released when calls end — check for stuck busy rows after hangup.
  3. Reduce concurrency or raise the ceiling. Smooth the burst if the traffic pattern is the cause, or contact your account manager to raise the operator limit if the ceiling is structurally too low for your agent count.

Fix — resolve presence, membership, and aux-code drift

The fastest recovery for VOICE_AGENT_UNAVAILABLE is usually a presence reset:
  1. Open the agent in the dashboard or call GET /api/v1/voice/agents/{id}.
  2. Verify the state you see matches the state the queue dispatch reads. If it does not, the in-memory registry and the audit table have drifted — the registry wins for live routing, but the dashboard may lag until the next write-through succeeds.
  3. If the agent is stuck in paused, resume them with POST /api/v1/voice/agents/{id}/status → available. If they are stuck in wrapup, either submit a disposition or wait for acd_queues.wrap_up_seconds to expire.
  4. Re-check queue membership and skills. Add the agent to the queue if missing, or align requiredSkills / minSkillLevel so the agent qualifies.
  5. Retry the call or wait for the next dispatcher tick. Voice queue dispatch runs on a periodic scan, so a state fix can take one tick to reflect.
For VOICE_AGENT_MISSING, the fix is provisioning hygiene: remove stale ids from queue memberships and routing rules. For VOICE_OPERATOR_LIMIT_EXCEEDED, the fix is capacity management: release stuck agents or raise the ceiling.

What to capture before escalating

If the checks above do not clear the code, open a ticket with:
  1. The full error body — code, message, and the details object (agent id, limit, current count, queue id).
  2. The call id and queue id from the call detail view or the voice gateway log.
  3. The agent id the dispatcher tried to claim.
  4. The agent’s current state as shown in the dashboard and as returned by GET /api/v1/voice/agents/{id}.
  5. Your organization ID (Settings → Organization, or organizationId from GET /api/v1/me).

What not to do

  • Do not retry the call blindly. VOICE_AGENT_MISSING and VOICE_AGENT_UNAVAILABLE repeat until the underlying agent record or state changes.
  • Do not assume one queue’s state overrides another. Dispatch takes the worst state across memberships; fixing one queue does not clear a paused row on another.
  • Do not treat VOICE_OPERATOR_LIMIT_EXCEEDED as a queue-specific problem. The ceiling is tenant-scoped, not per-queue.
  • Do not change the call destination to work around the refusal. The destination already reached the queue; the issue is agent placement.

See also