Integrate the SDK

Errors

When something fails in a session — while it starts, while it runs, or when a request you made is rejected — it reaches your code as one typed error. You catch it, explain it to the user in your own words, and branch on it; every code it can carry is listed below.

The error object

Every error is one object:

Tip

Codes are stable — branch on error.code, never on the wording of error.message, which may change.

The phase tells you when the error happened — the same code can mean a failed start or a dropped connection mid-session:

PhaseWhen
startCreating the session, opening its connections, or starting the microphone.
recoverRe-establishing a session Speechineer had dropped.
connectionA connection failed while the session was running.
actionA request you made was rejected.
endFinishing the session.
runtimeSpeechineer stopped the session; it cannot continue and recoverable is false.

Listen for errors

However a session fails, you never have to hunt for the error: the same object is delivered to three places, each suited to a different job — a callback for reacting the moment something fails, the session state for rendering, and the rejected promise for the code that asked. Use whichever fits the code you are writing.

  • The onError callback — called the moment it happens. Log the error or send it to analytics from there:
    ts
    const voice = useSpeechToForm({
      form: intakeForm,
      onError: (error) => showBanner(error.code, error.recoverable),
    });
  • The session state — the error sits there as error and stays until the next start() succeeds. Render your message from there — describe is your own mapping from a code to your wording:
    tsx
    {voice.error && <p role="alert">{describe(voice.error.code)}</p>}
  • The rejected promisestart() and end() reject with the same error, so an await where you call them catches it directly:
    tsx
    const onSpeak = async () => {
      try {
        await voice.start();
      } catch (error) {
        showBanner(error.code, error.recoverable);
      }
    };

Error codes

Grouped by what you should do about them. The codes are frozen: they will not change under you.

In the browser

Raised by the SDK itself. Fix locally; most are worth a retry button.

CodeMeaningPossible fix
MICROPHONE_DENIEDMicrophone access was blocked, or the page is not on a secure origin (HTTPS or localhost). Recoverable — ask again.Serve over HTTPS or localhost and surface the browser's permission prompt again. error.recoverable is true — offer a retry button.
MICROPHONE_UNAVAILABLENo usable microphone was found.Ask the user to plug in or enable a microphone, then retry; check the browser's device permissions.
AUDIO_UNSUPPORTEDThis browser cannot record audio in the required format.Ask the user to switch to a current browser; no configuration on your side changes this.
NETWORKThe request never got an answer — connectivity, or the browser blocked the request (check its console). Recoverable.If the browser console shows a blocked cross-origin request, your origin was refused — check baseUrl for typos and tell us the origin you serve from. Otherwise check connectivity and retry.
NO_SESSIONAn action was called before start().Call start() before stop(), end() or any other action, or guard the action on the session's state.
NO_CLIENTNo client is provided above this component — the provider / provide call is missing.Wrap the component in the provider (React), call the provide function at bootstrap (Angular), or pass the client explicitly.

Authentication

Fix the auth token or key configuration; do not retry unchanged.

CodeMeaningPossible fix
AUTH_REQUIREDNo auth token was presented.Pass the API key to createClient — or, in Signed mode, make sure your token endpoint returns a token.
API_KEY_INVALIDThe API key in the token is unknown or inactive.Check the key against API keys in your workspace; create a new one if it was deactivated or archived.
AUTH_SIGNATURE_REQUIREDThe workspace or key requires a PS256-signed token; alg=none was presented.This page needs a Signed key: mint PS256 tokens in your backend with a signing key, or use an Unsigned key only where the workspace allows it.
AUTH_MODE_MISMATCHThe token's alg does not match the API key's auth mode (Signed keys accept only PS256; Unsigned keys only alg=none).Check which client the page resolves and which mode its key carries — one app can hold both (see Authentication).
AUTH_ENVELOPE_INVALIDThe token is malformed, or its claims are missing or wrong.Compare the claims your backend signs with the reference set (api_key, account_key, aud, iat, exp, jti) and the alg / kid header.
AUTH_ENVELOPE_REPLAYEDThis token was already used (replayed `jti`).Mint a fresh token per session start with a unique jti; never cache a token across sessions.
AUTH_ENVELOPE_LIFETIME_EXCEEDEDThe token is valid for longer than the maximum allowed lifetime.Shorten exp − iat in your backend; a few minutes is plenty, the SDK asks for a new token every start.
ACCOUNT_REQUIREDThe token does not name an account.Add the account claim to the token (Signed) or pass account.key to createClient (Unsigned).
SIGNING_KEY_NOT_FOUNDThe token's key id matches no active signing key in the workspace.Put the signing key's id in the token's kid header, and check the key is still active in Signing keys.

Quotas and billing

Surface to the user or your operations; retrying will not help until limits change.

CodeMeaningPossible fix
API_KEY_QUOTA_EXCEEDEDThe API key's units limit is reached.Raise or remove the key's units limit in its settings, or wait for the period to roll over.
WORKSPACE_QUOTA_EXCEEDEDThe workspace units limit is reached.Raise the workspace limit in its settings, or wait for the period to roll over.
ACCOUNT_QUOTA_EXCEEDEDThe account's units limit is reached.Raise the account's limit from your backend or in Accounts; tell the user their allowance is used up.
FORM_QUOTA_EXCEEDEDThe form's units limit is reached.Raise the form's units limit in its settings, or wait for the period to roll over.
PLAN_ALLOWANCE_EXHAUSTEDIncluded units are used up and no prepaid units remain.Buy prepaid units or wait for the next cycle; the dashboard shows what remains.
OVERSPEND_LIMIT_REACHEDThe configured overspend cap is reached.Raise the overspend cap in Billing, or wait for the next cycle.
CONCURRENCY_LIMIT_REACHEDToo many workflows are running concurrently.End sessions you no longer need, queue starts on your side, or ask for a higher concurrency limit.

Form and workflow resolution

Check the form key, version, language, and workflow configuration.

CodeMeaningPossible fix
FORM_NOT_FOUNDNo form with this key in the workspace.Compare form.key with the key shown on the form's page; a key belongs to one workspace only.
FORM_VERSION_NOT_PUBLISHEDThe version your code names exists but is a draft.Publish it from the form's header (Publish this version), or point version at the published one.
NO_PUBLISHED_VERSION_FOR_LANGUAGENo published version exists for the requested language.Add the language to the form and publish, or request a language the published version supports.
FORM_KEY_PORTAL_OWNEDThis form is configured in Speechineer — use source: "workspace" for it.Name the form with source: "workspace" instead of passing an inline definition under that key.
WORKFLOW_NOT_FOUNDThe requested workflow does not exist.Check the workflow name; leave it unset to get the default.
WORKFLOW_STANDALONE_MODE_UNSUPPORTEDThis workflow has no standalone mode.Use a workspace form for this workflow; inline definitions are not supported here.
SESSION_NOT_FOUNDThe workflow you tried to resume no longer exists.Start a new session instead of resuming; the previous one has expired.

Lifecycle

The component is deactivated or archived — resolve in your workspace.

CodeMeaningPossible fix
WORKSPACE_INACTIVEThe workspace is deactivated or archived.Reactivate the workspace in its settings; an archived workspace cannot be brought back — create a new one.
CLIENT_INACTIVEThe owning organization is deactivated.Contact your organization's owner; nothing on the page side fixes this.
COMPONENT_ARCHIVEDA write was attempted on an archived component.Archived is final. Create a new form, key or account and point your code at it.