{"record":{"id":"c8dae209887c9c71","repo":"moeru-ai/airi","slug":"failed-to-fetch-voices-response-statustext","errorCode":null,"errorMessage":"Failed to fetch voices: ${response.statusText}","messagePattern":"Failed to fetch voices: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/libs/providers/providers/index-tts-vllm/index.ts","lineNumber":81,"sourceCode":"\n          return { errors: [], reason: '', reasonKey: '', valid: true }\n        },\n      }),\n    ],\n  },\n  extraMethods: {\n    listModels: async () => [{\n      id: 'IndexTTS-1.5',\n      name: 'IndexTTS-1.5',\n      provider: 'index-tts-vllm',\n      description: 'Default model for Index-TTS vLLM deployment',\n      contextLength: 0,\n      deprecated: false,\n    }],\n    listVoices: async (config) => {\n      const response = await fetch(voicesUrl(config))\n      if (!response.ok)\n        throw new Error(`Failed to fetch voices: ${response.statusText}`)\n\n      const voices = await response.json() as Record<string, unknown>\n      return Object.keys(voices).map(voice => ({\n        id: voice,\n        name: voice,\n        provider: 'index-tts-vllm',\n        languages: [{ code: 'cn', title: 'Chinese' }, { code: 'en', title: 'English' }],\n      }))\n    },\n  },\n})\n","sourceCodeStart":63,"sourceCodeEnd":93,"githubUrl":"https://github.com/moeru-ai/airi/blob/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-ui/src/libs/providers/providers/index-tts-vllm/index.ts#L63-L93","documentation":"listVoices fetches voicesUrl(config) — an HTTP endpoint on the user's self-hosted Index-TTS vLLM deployment — and throws with statusText when the response is not OK. statusText is often empty on HTTP/2, so the message may carry little detail. The signature is: the host is reachable but this specific route is not available.","triggerScenarios":"baseURL points at the wrong port or path so the voices route resolves to a 404; the deployed vLLM IndexTTS build does not expose a voices route; the endpoint requires auth and returns 401/403; a proxy in front returns 502.","commonSituations":"Local vLLM server not started or started without the IndexTTS routes; base URL copied from a different project with another path prefix; corporate proxy intercepting the endpoint.","solutions":["curl the voices URL from the same machine to see the actual status","Fix the provider's baseURL (scheme, host, port, path) in settings","Deploy a vLLM build that implements the IndexTTS voices route","Ensure no auth header or proxy requirement blocks the endpoint"],"exampleFix":"// before\nbaseUrl: 'http://localhost' // wrong port → voices route 404\n\n// after\nbaseUrl: 'http://localhost:8000' // verify with: curl http://localhost:8000/voices","handlingStrategy":"validation","validationCode":"try {\n  const probe = await fetch(voicesUrl(config), { method: 'HEAD' })\n  if (!probe.ok) showConfigError('Voices endpoint not available — check baseURL')\n}\ncatch {\n  showConfigError('Cannot reach the vLLM server')\n}","typeGuard":null,"tryCatchPattern":"try {\n  const voices = await provider.extraMethods.listVoices(config)\n}\ncatch (err) {\n  // Distinguish HTTP rejection (this error) from network refusal:\n  // HTTP rejection means the deployment or path is wrong, not the network.\n  toast('Voices endpoint rejected the request — verify baseURL and deployment')\n}","preventionTips":["Add a Test connection button that probes the voices route when saving settings","Normalize baseURL — strip trailing slashes, default scheme — before composing URLs","Document which IndexTTS vLLM builds expose the voices route"],"tags":["indextts","vllm","self-hosted","voices","base-url"],"backgroundTag":"wrong-base-url","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}