Speko Docs

Errors

SpekoClientError and its error codes.

The client SDK throws a single error class, SpekoClientError, tagged with a stable string code.

import { SpekoClientError } from '@spekoai/client';
import type { SpekoClientErrorCode } from '@spekoai/client';

Shape

class SpekoClientError extends Error {
  code: SpekoClientErrorCode;
  cause?: unknown;   // original error when wrapping transport failures
}

Codes

CodeWhere it's thrown
CONNECTION_FAILEDVoiceConversation.create() — transport connection rejected. cause is the original transport error.
MICROPHONE_FAILEDcreate() — mic acquisition or publishTrack() failed. The room is disconnected before this is thrown.
NOT_CONNECTEDsendUserMessage / sendContextualUpdate / internal publish() called while status isn't connected.
INVALID_MESSAGENo longer raised. Malformed inbound data packets are silently ignored (rooms carry non-protocol data from other publishers). Kept in the type for compatibility.
DISCONNECTEDReserved for future use.

Fatal vs non-fatal

  • Fatal errors (connection and microphone failures during create()) are thrown from the create() promise so callers can branch at construction time.
  • Non-fatal errors (media device errors from the transport) are routed to onError. The session continues.
  • Non-protocol data packets (malformed JSON, unknown shapes from other publishers in the room) are silently ignored — they never reach onError.

Example

try {
  const conv = await VoiceConversation.create({ ... });
} catch (err) {
  if (err instanceof SpekoClientError) {
    switch (err.code) {
      case 'CONNECTION_FAILED':
        // Token expired, network issue, or transport outage — ask user to retry.
        break;
      case 'MICROPHONE_FAILED':
        // Permission denied or device in use — surface a permissions prompt.
        break;
    }
  }
  throw err;
}

On this page