or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

audio

audio-processing.mdrealtime-transcription.mdspeech-to-speech.mdspeech-to-text.mdtext-to-speech.md
index.md
tile.json

errors.mddocs/core/

Error Handling

Comprehensive error handling for the ElevenLabs SDK with specific error classes for each HTTP status code.

Error Classes

Base Error Classes

/**
 * Base error class for all ElevenLabs errors
 */
class ElevenLabsError extends Error {
  statusCode?: number;
  body?: unknown;
  rawResponse?: Response;
}

/**
 * Timeout error when request exceeds configured timeout
 */
class ElevenLabsTimeoutError extends Error {}

Import Error Classes

Base error classes can be imported directly:

import {
  ElevenLabsError,
  ElevenLabsTimeoutError,
} from "@elevenlabs/elevenlabs-js";

HTTP-specific error classes are accessed via the ElevenLabs namespace:

import { ElevenLabs } from "@elevenlabs/elevenlabs-js";

// Available error classes:
// ElevenLabs.BadRequestError, ElevenLabs.UnauthorizedError,
// ElevenLabs.ForbiddenError, ElevenLabs.NotFoundError,
// ElevenLabs.ConflictError, ElevenLabs.UnprocessableEntityError,
// ElevenLabs.TooEarlyError

HTTP Error Classes

/**
 * HTTP 400 - Bad Request
 */
class BadRequestError extends ElevenLabsError {
  statusCode: 400;
}

/**
 * HTTP 401 - Unauthorized (invalid or missing API key)
 */
class UnauthorizedError extends ElevenLabsError {
  statusCode: 401;
}

/**
 * HTTP 403 - Forbidden (insufficient permissions)
 */
class ForbiddenError extends ElevenLabsError {
  statusCode: 403;
}

/**
 * HTTP 404 - Not Found (resource doesn't exist)
 */
class NotFoundError extends ElevenLabsError {
  statusCode: 404;
}

/**
 * HTTP 409 - Conflict (resource conflict)
 */
class ConflictError extends ElevenLabsError {
  statusCode: 409;
}

/**
 * HTTP 422 - Unprocessable Entity (validation failed, most common)
 */
class UnprocessableEntityError extends ElevenLabsError {
  statusCode: 422;
}

/**
 * HTTP 425 - Too Early (request sent too early)
 */
class TooEarlyError extends ElevenLabsError {
  statusCode: 425;
}

Error Handling Patterns

Basic Error Handling

import { ElevenLabsClient, ElevenLabsError, ElevenLabsTimeoutError } from "@elevenlabs/elevenlabs-js";

const client = new ElevenLabsClient({ apiKey: "your-api-key" });

try {
  const audio = await client.textToSpeech.convert(voiceId, { text: "Hello" });
} catch (error) {
  if (error instanceof ElevenLabsError) {
    console.error(`API Error ${error.statusCode}:`, error.body);
  } else if (error instanceof ElevenLabsTimeoutError) {
    console.error('Request timed out');
  } else {
    console.error('Unknown error:', error);
  }
}

Specific HTTP Error Handling

import { ElevenLabs, ElevenLabsTimeoutError } from "@elevenlabs/elevenlabs-js";

try {
  const audio = await client.textToSpeech.convert(voiceId, { text: "Hello" });
} catch (error) {
  if (error instanceof ElevenLabs.UnauthorizedError) {
    console.error('Invalid API key - check your credentials');
  } else if (error instanceof ElevenLabs.UnprocessableEntityError) {
    console.error('Validation failed:', error.body);
  } else if (error instanceof ElevenLabs.NotFoundError) {
    console.error('Voice not found - check voice ID');
  } else if (error instanceof ElevenLabs.ForbiddenError) {
    console.error('Insufficient permissions for this resource');
  } else if (error instanceof ElevenLabsTimeoutError) {
    console.error('Request timed out - try increasing timeout');
  } else {
    console.error('Unexpected error:', error);
  }
}

Accessing Error Details

try {
  const audio = await client.textToSpeech.convert(voiceId, { text: "Hello" });
} catch (error) {
  if (error instanceof ElevenLabsError) {
    // Access status code
    console.log('Status:', error.statusCode);

    // Access response body with error details
    console.log('Error body:', error.body);

    // Access raw HTTP response
    if (error.rawResponse) {
      console.log('Response headers:', error.rawResponse.headers);
    }
  }
}

Retry Logic

async function withRetry<T>(
  fn: () => Promise<T>,
  maxAttempts: number = 3,
  delayMs: number = 1000
): Promise<T> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      // Retry on timeout or server errors (5xx)
      const shouldRetry =
        error instanceof ElevenLabsTimeoutError ||
        (error instanceof ElevenLabsError && error.statusCode >= 500);

      if (shouldRetry && attempt < maxAttempts) {
        await new Promise(resolve => setTimeout(resolve, delayMs * attempt));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

// Usage
const audio = await withRetry(() =>
  client.textToSpeech.convert(voiceId, { text: "Hello" })
);

Common Error Scenarios

401 Unauthorized

Cause: Invalid or missing API key Solution: Check your API key is correct and has not expired

try {
  const audio = await client.textToSpeech.convert(voiceId, { text: "Hello" });
} catch (error) {
  if (error instanceof ElevenLabs.UnauthorizedError) {
    // Refresh API key or prompt user to re-authenticate
    console.error('Authentication failed - please check your API key');
  }
}

404 Not Found

Cause: Resource (voice, history item, etc.) does not exist Solution: Verify the ID is correct

try {
  const voice = await client.voices.get(voiceId);
} catch (error) {
  if (error instanceof ElevenLabs.NotFoundError) {
    console.error(`Voice ${voiceId} not found`);
    // Fallback to default voice or list available voices
  }
}

422 Unprocessable Entity

Cause: Validation error - most common error type Solution: Check error.body for validation details

try {
  const audio = await client.textToSpeech.convert(voiceId, {
    text: "", // Invalid: empty text
  });
} catch (error) {
  if (error instanceof ElevenLabs.UnprocessableEntityError) {
    console.error('Validation error:', error.body);
    // error.body typically contains field-specific error messages
  }
}

Timeout Error

Cause: Request exceeded configured timeout Solution: Increase timeout or optimize request

try {
  const audio = await client.music.compose({
    prompt: "Epic orchestral soundtrack",
    duration: 300, // 5 minutes
  }, {
    timeoutInSeconds: 600, // Increase timeout for long requests
  });
} catch (error) {
  if (error instanceof ElevenLabsTimeoutError) {
    console.error('Request timed out - consider shorter duration or longer timeout');
  }
}

403 Forbidden

Cause: Insufficient permissions or tier restrictions Solution: Check subscription tier or resource access

try {
  const audio = await client.textToSpeech.convert(voiceId, {
    text: "Hello",
    outputFormat: "pcm_44100", // Requires Pro+ tier
  });
} catch (error) {
  if (error instanceof ElevenLabs.ForbiddenError) {
    console.error('Feature requires higher subscription tier or different permissions');
  }
}

Error Recovery Strategies

Graceful Degradation

async function synthesizeSpeech(text: string, preferredVoiceId: string, fallbackVoiceId: string) {
  try {
    return await client.textToSpeech.convert(preferredVoiceId, { text });
  } catch (error) {
    if (error instanceof ElevenLabs.NotFoundError || error instanceof ElevenLabs.ForbiddenError) {
      console.warn('Falling back to default voice');
      return await client.textToSpeech.convert(fallbackVoiceId, { text });
    }
    throw error;
  }
}

Request Validation

function validateTextToSpeechRequest(text: string): void {
  if (!text || text.trim().length === 0) {
    throw new Error('Text cannot be empty');
  }
  if (text.length > 5000) {
    throw new Error('Text exceeds maximum length of 5000 characters');
  }
}

// Use before API call
try {
  validateTextToSpeechRequest(text);
  const audio = await client.textToSpeech.convert(voiceId, { text });
} catch (error) {
  // Handle validation errors before making API call
  console.error('Validation error:', error.message);
}

Related Documentation

  • Client Setup - Configure default timeouts and retries
  • Request Options - Override defaults per-request
  • Response Handling - Access raw responses and status codes