Errors
Every Ear3 package that can fail to start an interview — @ear3/voice-interviewer
(branded widget + headless) — surfaces the same error contract,
because they all go through the same session-mint endpoint
(POST /api/v1/interviews/:id/sessions). This page is the canonical
reference for that contract. Package pages link back here instead of
repeating the table.
Ear3VoiceError
onError fires with an Ear3VoiceError — a real Error instance
(instanceof Error holds, so it plays nicely with Sentry / error
boundaries / try/catch), not a plain { code, message } object:
export class Ear3VoiceError extends Error {
code: Ear3ErrorCode | string
message: string
status?: number // HTTP status, when the failure came from the API
cause?: unknown
}Ear3ErrorCode is a closed set of string literals, also exported at
runtime as Ear3ErrorCodes for plain-JS consumers and ===
comparisons:
import { Ear3ErrorCodes, type Ear3VoiceError } from '@ear3/voice-interviewer'
client.on('error', (err: Ear3VoiceError) => {
if (err.code === Ear3ErrorCodes.INTERVIEW_EXPIRED) {
showExpiredBanner()
} else {
showGenericError(err.message)
}
})Session mint failure
POST /api/v1/interviews/:id/sessions
code | HTTP | Meaning |
|---|---|---|
invalid_request | 400 | Missing/invalid params (e.g. no publishableKey) |
invalid_api_key | 401 | Key not found, revoked, or malformed |
invalid_key_type | 401 | A secret/webhook key was used in the browser — use a pk_ key |
interview_not_found | 404 | No interview with this id — often a survey id, not a deployment id |
workspace_mismatch | 403 | Key and interview belong to different workspaces |
interview_inactive | 409 | The interview is deployed but paused / not ACTIVE |
interview_expired | 410 | The interview’s deployment has passed its expiresAt |
subscription_inactive | 403 | The workspace’s subscription is not active |
limit_exceeded | 403 | Workspace hit its interview-time limit |
period_expired | 403 | The workspace’s billing period ended |
payment_failed | 403 | Payment needs attention |
upstream_error | 5xx | The voice backend (Pipecat) failed to start |
internal_error | 500 | Unexpected server error, or a 2xx mint response missing its transport params |
network_error | — | Client-only — the mint request never reached the server |
message is the server’s own text when present, otherwise a sensible
default (see EAR3_ERROR_MESSAGES, also exported). For symptom-first
debugging of these same codes (what you see in the browser, what to
click in the dashboard), see Troubleshooting.
WebRTC connection failure
Network issues, a firewall, or WebRTC being blocked outright. onError
fires with code: 'unknown' (or http_<status> when RTVI reports one)
and a message describing the transport issue. The PipecatClient will
already have called disconnect() by the time you get the callback.
Bot preempted mid-conversation
RTVI emits
bot-disconnected. VoiceClient transitions to ended. Call
connect() again to restart — a new session is minted server-side.
Related
- @ear3/voice-interviewer — headless client,
VoiceClientstate machine - Troubleshooting — symptom-first failure modes