{"record":{"id":"a191c4e278822400","repo":"moeru-ai/airi","slug":"speech-engine-answered-response-status-respon","errorCode":null,"errorMessage":"Speech engine answered ${response.status} ${response.statusText} for /${engineRequest.endpoint}${suffix}","messagePattern":"Speech engine answered (.+?) (.+?) for /(.+?)(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/libs/providers/providers/voicevox/engine.ts","lineNumber":207,"sourceCode":"    throw new Error('The Base URL is not an absolute http:// or https:// address.')\n  }\n\n  const doFetch = options?.fetch ?? globalThis.fetch\n  const response = await doFetch(url, {\n    method: POST_ENDPOINTS.has(engineRequest.endpoint) ? 'POST' : 'GET',\n    // No engine in the family redirects. A redirect therefore means the Base URL\n    // points at something else, and following it would hide that.\n    redirect: 'error',\n    signal: options?.signal,\n    ...(engineRequest.body === undefined\n      ? {}\n      : { body: JSON.stringify(engineRequest.body), headers: { 'Content-Type': 'application/json' } }),\n  })\n\n  if (!response.ok) {\n    const detail = (await response.text()).trim()\n    const suffix = detail ? `: ${detail.slice(0, 200)}` : ''\n    throw new Error(`Speech engine answered ${response.status} ${response.statusText} for /${engineRequest.endpoint}${suffix}`)\n  }\n\n  return response\n}\n","sourceCodeStart":189,"sourceCodeEnd":212,"githubUrl":"https://github.com/moeru-ai/airi/blob/9c213115f8bd0fff9e6eabab02b077ac32da21be/packages/stage-ui/src/libs/providers/providers/voicevox/engine.ts#L189-L212","documentation":"request() treats any non-ok HTTP response as fatal and throws with the status, statusText, endpoint, and up to 200 chars of the response body as detail. This is the generic engine-side error surface: the request reached a VOICEVOX-compatible engine but the engine rejected it (or an intermediary rejected it).","triggerScenarios":"Any endpoint returning 4xx/5xx: /audio_query with an unknown speaker id (400/404/422), engine overloaded (500/503), unsupported endpoint on a compatible engine like CoqPIt/ShareVOX (404), auth/proxy rejection (401/403).","commonSituations":"Voice id from a different engine version (speaker id no longer exists); engine still initializing; style id out of range; Base URL behind a proxy that strips or blocks POST; wrong engine family exposing different endpoint paths.","solutions":["Read the `: <detail>` suffix in the message — it contains the engine's own error text identifying the root cause.","Re-fetch the speaker list from the engine (/speakers) and re-select the voice so ids match the running engine.","Confirm the Base URL points at the intended engine and version; restart the engine if it returns 500/503.","If using a proxy, ensure it forwards POST bodies with Content-Type application/json untouched."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await synthesize(request)\n}\ncatch (error) {\n  const message = errorMessageFrom(error)\n  const match = message.match(/answered (\\d{3})/)\n  if (match?.[1] === '404')\n    await refreshSpeakersAndReselectVoice()\n  else\n    showSpeechError(message)\n}","preventionTips":["Parse the `: <detail>` suffix for the engine's own error explanation.","Refresh the speaker list whenever the engine version or instance changes.","Add retry with backoff only for 5xx statuses, not 4xx.","Monitor engine health (GET /version) before synthesis sessions."],"tags":["network","http","voicevox","api-error"],"backgroundTag":"http-4xx-5xx-response","analyzedSha":"9c213115f8bd0fff9e6eabab02b077ac32da21be","analyzedAt":"2026-09-02T04:27:24.639Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}