moeru-ai/airi · error · TtsUpstreamResponseError
TtsUpstreamResponseError (rethrown upstream response body wi
Error message
TtsUpstreamResponseError (rethrown upstream response body with upstream status/headers)
What it means
`TtsUpstreamResponseError` is the adapter's normalized wrapper for a non-OK response returned by the upstream TTS provider reached through the unspeech SDK. `sendSpeechViaUnSpeech` catches `UnSpeechAPIError` and rethrows it as this error carrying a reconstructed `Response` with the upstream status, body, and headers, so the router can apply its HTTP 500 fallback policy while preserving the upstream's actual error payload.
Source
Thrown at server/apps/api/src/services/adapters/tts/unspeech.ts:76
speed,
voice,
abortSignal: ctx.abortSignal,
extraBody,
})
return {
contentType: result.contentType ?? fallbackContentType,
body: result.body,
}
}
catch (error) {
// Keep abort identity intact so the router can apply `onTimeout`
// independently from HTTP 500 fallback policy.
if (ctx.abortSignal?.aborted)
throw error
if (error instanceof UnSpeechAPIError) {
throw new TtsUpstreamResponseError(new Response(error.responseBody, {
status: error.status,
headers: error.responseHeaders,
}))
}
throw createInternalError(`${providerLabel} tts fetch failed: ${errorMessageFrom(error) ?? 'unknown'}`)
}
}
interface ListVoicesOptions {
ctx: TtsVoiceCatalogContext
query: string
providerLabel: string
}
/**
* Lists unspeech voices and maps SDK failures into AIRI gateway errors.
*View on GitHub (pinned to f679616c34)
Solutions
- Inspect the wrapped Response's status and body to read the upstream's own error message, then fix the matching cause (key, voice, model).
- Verify the upstream API key stored in LLM router config is valid and not expired.
- Check that the requested voice/model exist in the provider catalog (list voices via the adapter's /audio/voices path).
- If status is 429 or 5xx, retry after backoff; the router may fall back to the next upstream in the chain.
- Confirm `ctx.unspeechBaseURL` points to the correct unspeech-compatible endpoint.
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
// validate upstream config before dispatch
if (!ctx.keyPlaintext?.length) throw createInternalError('missing upstream TTS API key')
if (!ctx.unspeechBaseURL) throw createInternalError('missing unspeech base URL') Type guard
function isTtsUpstreamResponseError(e: unknown): e is TtsUpstreamResponseError { return e instanceof TtsUpstreamResponseError } Try / catch
try {
const result = await sendSpeechViaUnSpeech(options)
} catch (error) {
if (error instanceof TtsUpstreamResponseError) {
const status = error.response.status
if (status === 429 || status >= 500) return retryWithNextUpstream(error)
return new Response(error.response.body, { status, headers: error.response.headers })
}
throw error
} Prevention
- Validate that the requested voice/model exist in the provider's voice catalog before calling the upstream.
- Rotate and verify upstream API keys stored in the encrypted router config.
- Implement upstream-chain fallback for 429/5xx statuses at the router level.
- Log the upstream response body on failure to speed up provider-side diagnosis.
When it happens
Trigger: The unspeech `generateSpeechResponse` call receives an HTTP error response from the upstream provider: invalid/expired upstream API key, unknown model or voice id for that provider, provider-side quota/rate limit, or malformed `extraBody` rejected by the upstream.
Common situations: Encrypted upstream key (`ctx.keyPlaintext`) is wrong or revoked; requested voice does not exist for the configured provider/region; upstream provider outage returning 4xx/5xx; base URL misconfigured so requests hit the wrong upstream endpoint.
Related errors
- Gemini TTS request failed: ${response.status} ${await respon
- MiMo TTS request failed: ${response.status} ${response.statu
- Gemini TTS request failed: ${response.status} ${await respon
- MiMo TTS request failed: ${response.status} ${response.statu
- MiniMax TTS request failed: ${response.status} ${response.st
AI-assisted analysis of moeru-ai/airi@f679616c34 (2026-09-08).
Data as JSON: /api/errors/eaacbc306196eb89.
Report an issue: GitHub.