{"record":{"id":"51c8be96f1f8b454","repo":"nexu-io/open-design","slug":"elevenlabs-voices-resp-status-errtext-slice","errorCode":null,"errorMessage":"elevenlabs voices ${resp.status}: ${errText.slice(0, 240)}","messagePattern":"elevenlabs voices (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/integrations/elevenlabs-voices.ts","lineNumber":137,"sourceCode":"    pageSize,\n  });\n  const cached = voiceOptionsCache.get(cacheKey);\n  const now = Date.now();\n  if (cached && cached.expiresAt > now) {\n    return cloneVoiceOptions(cached.voices);\n  }\n\n  const resp = await fetch(`${baseUrl}/v2/voices?page_size=${pageSize}`, {\n    ...options.requestInit,\n    method: 'GET',\n    headers: {\n      'xi-api-key': credentials.apiKey,\n      accept: 'application/json',\n    },\n  });\n  if (!resp.ok) {\n    const errText = await resp.text();\n    throw new Error(`elevenlabs voices ${resp.status}: ${errText.slice(0, 240)}`);\n  }\n\n  const payload = await resp.json() as unknown;\n  const rawVoices = isRecord(payload) && Array.isArray(payload.voices)\n    ? payload.voices\n    : [];\n  const voices = rawVoices\n    .map((voice) => normalizeVoice(voice))\n    .filter((voice): voice is ElevenLabsVoiceOption => voice !== null);\n  voiceOptionsCache.set(cacheKey, {\n    expiresAt: now + ELEVENLABS_VOICE_CACHE_TTL_MS,\n    voices: cloneVoiceOptions(voices),\n  });\n  return voices;\n}\n","sourceCodeStart":119,"sourceCodeEnd":153,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/integrations/elevenlabs-voices.ts#L119-L153","documentation":"Thrown by listElevenLabsVoiceOptions() when the GET to {baseUrl}/v2/voices?page_size=N returns a non-ok response. The first 240 chars of the response body are embedded so the operator can see ElevenLabs' error detail (rate limit, invalid key, wrong base URL).","triggerScenarios":"ElevenLabs returns 401 (invalid xi-api-key), 429 (rate limit / quota), 404 (custom baseUrl that does not host /v2/voices), or 5xx. Also when a proxy baseUrl (e.g. an OpenAI-compatible gateway) is set for elevenlabs but does not implement the /v2/voices route.","commonSituations":"Expired or revoked API key; free-tier rate limit during catalogue refresh; baseUrl pointing at a ElevenLabs-compatible proxy that lacks the voices route; transient 5xx during an ElevenLabs incident.","solutions":["Inspect the embedded status/body: 401 → rotate the key, 429 → back off and cache longer, 404 → fix baseUrl.","Confirm baseUrl (credentials.baseUrl or https://api.elevenlabs.io) actually serves /v2/voices.","Rely on the in-memory voice cache (TTL 10 min) to ride through short outages instead of re-fetching on every call."],"exampleFix":"// before\nconst resp = await fetch(`${baseUrl}/v2/voices?page_size=${pageSize}`, ...);\nif (!resp.ok) throw new Error(`elevenlabs voices ${resp.status}: ${errText.slice(0, 240)}`);\n\n// after\nif (!resp.ok) {\n  const cached = voiceOptionsCache.get(cacheKey);\n  if (cached && cached.expiresAt > Date.now()) return cached.voices;\n  throw new Error(`elevenlabs voices ${resp.status}: ${errText.slice(0, 240)}`);\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"function isElevenLabsHttpError(err: unknown): boolean {\n  return err instanceof Error && /^elevenlabs voices \\d{3}:/.test(err.message);\n}\n\nfunction extractStatus(err: unknown): number | null {\n  const m = err instanceof Error ? err.message.match(/^elevenlabs voices (\\d{3}):/) : null;\n  return m ? Number(m[1]) : null;\n}","tryCatchPattern":"import { voiceOptionsCache } from '../integrations/elevenlabs-voices.js';\n\ntry {\n  return await listElevenLabsVoiceOptions(projectRoot);\n} catch (err) {\n  const status = extractStatus(err);\n  if (status && status >= 500) {\n    // transient — caller may retry; cache serves stale if present\n  }\n  throw err;\n}","preventionTips":["Rely on the 10-minute in-memory voice cache to absorb short outages.","Rotate keys before they expire to avoid 401s in production.","Confirm baseUrl actually serves /v2/voices before pointing ElevenLabs at a proxy."],"tags":["network","integration","http","elevenlabs"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}