decolua/9router · error

ElevenLabs API key required

Error message

ElevenLabs API key required

What it means

fetchElevenLabsVoices requires an ElevenLabs API key (sent as the `xi-api-key` header) and throws this error immediately when called with a falsy key. It is a guard against making an authenticated list-voices call without credentials, since ElevenLabs will only reject the request later with a 401.

Source

Thrown at open-sse/handlers/ttsProviders/elevenlabs.js:8

// ElevenLabs TTS — voice id with optional model_id prefix
import { Buffer } from "node:buffer";

const VOICES_TTL = 24 * 60 * 60 * 1000;
const _voicesCache = new Map(); // by API key

export async function fetchElevenLabsVoices(apiKey) {
  if (!apiKey) throw new Error("ElevenLabs API key required");
  const now = Date.now();
  const cached = _voicesCache.get(apiKey);
  if (cached && now - cached.time < VOICES_TTL) return cached.voices;

  const res = await fetch("https://api.elevenlabs.io/v1/voices", {
    headers: { "xi-api-key": apiKey, "Content-Type": "application/json" },
  });
  if (!res.ok) throw new Error(`ElevenLabs voices fetch failed: ${res.status}`);
  const data = await res.json();
  // Normalize: derive lang from labels for grouping
  const voices = (data.voices || []).map((v) => ({ ...v, lang: v.labels?.language || "en" }));
  _voicesCache.set(apiKey, { voices, time: now });
  return voices;
}

export default {
  async synthesize(text, model, credentials) {
    if (!credentials?.apiKey) throw new Error("ElevenLabs API key required");

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Enter a valid ElevenLabs API key in the 9Router dashboard credentials for the ElevenLabs provider.
  2. Verify the credential object shape: the code reads `credentials.apiKey` — ensure your key is stored under `apiKey`, not another field name.
  3. Test the key directly: `curl -H "xi-api-key: $KEY" https://api.elevenlabs.io/v1/voices` should return 200.
  4. If calling fetchElevenLabsVoices programmatically, pass the key explicitly: fetchElevenLabsVoices(process.env.ELEVENLABS_API_KEY).

Example fix

// before
const voices = await fetchElevenLabsVoices(creds.elevenKey); // undefined field
// after
const key = creds?.apiKey || process.env.ELEVENLABS_API_KEY;
if (!key) throw new Error("Set an ElevenLabs API key before listing voices");
const voices = await fetchElevenLabsVoices(key);
Defensive patterns

Strategy: validation

Validate before calling

function hasElevenLabsCredentials(creds) {
  return typeof creds?.apiKey === "string" && creds.apiKey.trim().length > 0;
}
if (!hasElevenLabsCredentials(creds)) throw new Error("Configure an ElevenLabs API key first");

Type guard

function hasApiKey(creds) {
  return typeof creds === "object" && creds !== null &&
    typeof creds.apiKey === "string" && creds.apiKey.length > 0;
}

Try / catch

try {
  const voices = await fetchElevenLabsVoices(apiKey);
} catch (e) {
  if (e.message === "ElevenLabs API key required") {
    // surface a config error to the user, not a 500
    return res.status(400).json({ error: "ElevenLabs provider is not configured — add an API key in the dashboard" });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling fetchElevenLabsVoices() (via the `voices` handler) with the ElevenLabs provider selected while no API key is configured — credentials missing, credentials present but the key field named incorrectly (e.g. `token` instead of `apiKey`), or an empty-string key stored in the dashboard.

Common situations: User enabled the ElevenLabs TTS provider in 9Router but never entered an API key; key stored under the wrong credential field after migration; key was deleted/blanked in the credentials UI; code path invoked programmatically without passing credentials.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/7b97472c4ae3edc5. Report an issue: GitHub.