Skip to main content

Troubleshooting: agent outbound-call and voice-clone guard codes

Three guard codes stop an agent call or a voice-clone request before any telephony or synthesis work begins. Each one blocks a different surface — the agent’s outbound-calling toggle, the agent’s guardrail envelope, and the voice-clone consent attestation — and each fails fast at the gate, so nothing downstream (a call record, a clone row, a synthesis credit) is created. This page tells you which gate fired, which surface to re-check, and when to escalate instead of retrying.

Code matrix — symptom to fix

Outbound calling disabled

POST /api/v1/agents/:id/calls is the agent-originating outbound-call endpoint. It walks a short chain of guards before it originates anything: the agent must exist (AGENT_NOT_FOUND 404), must not be archived (AGENT_ARCHIVED 400), and must have outbound calling switched on. The OUTBOUND_CALLING_DISABLED 409 fires on the last check — the toggle is a per-agent setting operators flip deliberately, and placing a call spends balance, so the route refuses to originate for a disabled agent instead of defaulting open. Symptoms:
  • The error message names one fix: enable the toggle.
  • Your integration is fine; the failure is repeatable until the toggle flips, so a retry loop returns the same 409 every time.
  • No call record, no billing event, no origination — the guard runs before any of those are touched.
Fix — enable the toggle, then re-send the call request:
The same endpoint reads the current state with GET, and carries the agent’s default caller ID alongside the toggle — set it with a caller_id field on the same PATCH body (send caller_id: null to clear and fall back to the tenant default). Verify the agent id from GET /api/v1/agents first; a bad id returns AGENT_NOT_FOUND, not this code. When to escalate instead: never for the toggle itself — it is a deliberate per-agent control, tenant-owned end to end. Escalate only if the PATCH route itself errors (a 4xx validation refusal, or a 5xx) or the toggle reads back true from the GET while POST .../calls still returns the 409 — that mismatch narrows the window to the update you made, so capture the PATCH response and one failing 409 envelope with its request id and timestamps. What NOT to try:
  • Do not treat the 409 as a rate limit or a carrier block and back off exponentially — it fires identically until the config changes.
  • Do not escalate a downstream guard (TCPA dialing window, balance, destination block) under this page — those have their own runbooks; this one owns only the pre-origination agent toggle.

Guardrail violation reserved code

GUARDRAIL_VIOLATION appears in the error codes catalog with the status varies, as a reserved AI-guardrail code. Reservation means the code is held in the platform’s error-code enum for SDK stability and forward compatibility — no public endpoint throws it today, and guardrail failures still surface through other codes. Confirmed facts:
  • No public endpoint (/chat, /invoke, graph test-run, voice-agent turn) throws it. Internal comments reference the stream path, but the code itself is unthrown — treat this page as triage.
  • Guardrail failures surface today as AI_PARSE_FAILED (422) or VALIDATION_ERROR (422) on the /chat / /invoke routes — parse or schema mismatches in the agent’s output, not residual guardrail verdicts on the envelope.
  • The reserved code’s HTTP status varies — expected 422 on /chat run-and-validate, 502 when the provider loop degrades.
If a customer’s API capture shows a literal GUARDRAIL_VIOLATION response:
  1. Capture the exact HTTP status, the message and details fields, and the request id off the envelope.
  2. Check whether the response came through an SDK or a wrapper that remaps the model’s structured output — the raw envelope matters more than the mapped shape.
  3. Escalate with the raw envelope and the two request ids bracketing the change to support — this code is not supposed to surface on end-user calls today, so a 422 with it is a platform signal, not a tenant config issue.
What NOT to try:
  • Do not write a fix branch that “handles” GUARDRAIL_VIOLATION on your /chat /invoke integration — the code is reserved, not thrown; the false guard branch is dead code.
  • Do not assume your agent is blocked by a guardrail because the code appears in the catalog — the catalog holds the reservation, not the live behavior.
Every voice-clone call (POST /api/v1/voice/clones for call-sourced cloning, POST /api/v1/voice/clones/upload for a sample upload, and any design or design- upload flow that lands on the same gate) runs a consent gate first — the attestation you send is validated before the route touches the database, a provider, or any credit. The gate throws 422 with VOICE_CLONE_CONSENT_REQUIRED when the attestation is missing or incomplete, and that is a deliberate fail-fast, not a transient condition. Attestation fields and the gate order:
  • biometric_consent_acknowledged must be true — the acknowledgement that your application carries biometric-privacy obligations (BIPA / CUBI / EU AI Act Art 50) for a cloned voice. Missing it throws with missing_field: "biometric_consent_acknowledged".
  • voice_owner_relationship must be a non-empty classify string — the route accepts the self | employee | actor_with_release | customer_with_written_consent | other vocabulary; any other input throws with missing_field: "voice_owner_relationship".
  • One of voice_owner_consent_evidence_url (an HTTPS URL to the written evidence — ≥50 characters for the text variant) or voice_owner_consent_text (a free-form attestation statement, ≥ 50 characters on a text-only attestation) must be present. Missing both throws with missing_field: "voice_owner_consent_evidence_url | voice_owner_consent_text"; a text that is too short or too long throws with field: "voice_owner_consent_text" plus the cap bound.
Symptoms:
  • The error is deterministic — missing attestation fields return it identically every time you retry.
  • The gate passes before any clone row is created, so a correct retry is a genuine first attempt, not a duplicate; you are never charged for a blocked request.
  • The route rejects both evidence text and evidence URL being absent — one of the two is required, and the attestation text cap is applied on both the length bounds.
Fix — fill the attestation fields on the retry. The attestation shape is the same compact body the route’s validation schema accepts; on the call-sourced path it travels with the source_call_id and on the upload path with the sample. Resubmit with every required field populated and a consent text at or above the length floor, or a HTTPS evidence URL that points at the signed consent. The error’s details.missing_field (or details.field on a length violation) names exactly which gate failed, so there is one retry per field — not several blind ones. When to escalate instead: never because of the gate itself — it is a tenant-owned consent control, and the customer fixes it in the request. Escalate if the API refuses every attestation shape you send, if the details names a field the schema does not validate, or if a 5xx replaces the 422 after a complete attestation — all of those narrow the fix to the route layer, not to your compliance posture.

Triage table — fix or escalate

The first two codes are deliberate, tenant-facing gates — flipping the right surface permanently retires them. The third is a reserved code that maps no runnable path today.

What NOT to try

  • Do not retry in a loop on the toggle codeOUTBOUND_CALLING_DISABLED fires identically on every request until the config changes; spend the backoff on the PATCH instead.
  • Do not write a fix branch for GUARDRAIL_VIOLATION — reserved codes are placeholders, not endpoints; the false branch is dead code.
  • Do not shorten the attestation text below the floor to beat the length cap — that field names its bound; the gate validates exactly one thing at a time, and the retry must carry all the required fields.

See also

  • Error codes reference — the catalog these codes live in; GUARDRAIL_VIOLATION is recorded as reserved there.
  • Voice biometrics failures — the sidecar connect / auth / availability codes on enroll and verify this page does not own.
  • The agent outbound-calling toggle on the dashboard — the same code the GET/PATCH route exposes: Voice agents → Agent → Outbound calling.
  • Voice destination blocks — the post-toggle 4xx lane when the caller id or destination is what actually blocks the dial.