moeru-ai/airi · error
Streaming model id missing backend prefix: ${requestedModel}
Error message
Streaming model id missing backend prefix: ${requestedModel} What it means
Format guard in the official streaming speech playground: streaming model ids must be shaped `<backend>/<resource>` (e.g. `volcengine/seed-tts-2.0`) because the trailing path segment is forwarded to the upstream as Volcengine's `api_resource_id`. The code computes `slashIndex = requestedModel.indexOf('/')` and refuses ids without a slash, deliberately, so a bare resource id never silently degrades to a wrong/default upstream resource — the comment in source calls this out as hiding config drift.
Source
Thrown at packages/stage-pages/src/pages/settings/providers/speech/official-provider-speech-streaming.vue:103
// Synthesize via the streaming session helper. The page uses the SAME
// transport the runtime pipeline uses (ws → API proxy → unspeech
// bridge → Volcengine v3 bidirectional) so the preview faithfully
// represents what the user hears in actual chat. The session is opened
// per-preview because there's no LLM token stream here — we just send
// one `text` frame containing the static preview prompt.
async function handleGenerateSpeech(input: string, voiceId: string, _useSSML: boolean): Promise<ArrayBuffer> {
const requestedModel = model.value
if (!requestedModel)
throw new Error('No streaming TTS model selected and server returned no default')
// `model` looks like `volcengine/seed-tts-2.0`. The trailing path is
// forwarded as Volcengine's `api_resource_id` so the upstream knows which
// model variant to use; matches the wiring in `Stage.vue`. We require the
// `<backend>/<resource>` shape and refuse anything else — silently picking
// a fallback resource id hides config drift.
const slashIndex = requestedModel.indexOf('/')
if (slashIndex < 0)
throw new Error(`Streaming model id missing backend prefix: ${requestedModel}`)
const apiResourceId = requestedModel.slice(slashIndex + 1)
const result = await streamingSynthesize({
model: requestedModel,
voice: voiceId,
input,
extraBody: {
api_resource_id: apiResourceId,
audio: { sample_rate: 24000, bit_rate: 64000 },
},
})
return result.audio
}
function handleLogin() {
needsLogin.value = true
}
</script>
View on GitHub (pinned to 677329427f)
Solutions
- Pick the model from the server-populated dropdown instead of typing one — catalog entries carry the `<backend>/<resource>` shape.
- If the stored value is stale, edit the provider config so `model` includes the backend prefix (e.g. `volcengine/seed-tts-2.0`).
- If catalog entries themselves arrive without a prefix, report the server bug — the client intentionally refuses to guess.
- Add a migration/default when reading stored config so legacy bare ids are upgraded rather than crashing at generate time.
Example fix
// before
const slashIndex = requestedModel.indexOf('/')
if (slashIndex < 0)
throw new Error(`Streaming model id missing backend prefix: ${requestedModel}`)
// after
if (!/^[a-z0-9-]+\/.+$/i.test(requestedModel))
throw new Error(`Streaming model id must look like '<backend>/<resource>', got: ${requestedModel}`) Defensive patterns
Strategy: type-guard
Validate before calling
const STREAMING_MODEL_ID_PATTERN = /^[a-z0-9-]+\/.+$/i const modelIdValid = computed(() => STREAMING_MODEL_ID_PATTERN.test(model.value ?? '')) // template: <button :disabled="!modelIdValid">Generate</button>
Type guard
function isStreamingModelId(id: string): boolean {
// '<backend>/<resource>' — backend segment non-empty, resource segment non-empty
return /^[^/\s]+\/.+[^/\s]$/.test(id) && !id.startsWith('/') && !id.endsWith('/')
} Try / catch
try { const apiResourceId = requestedModel.slice(requestedModel.indexOf('/') + 1) }
catch { /* validation happens before slicing; keep the explicit error message with the offending id */ } Prevention
- Only allow selecting catalog-provided ids; disable free-text entry of model ids.
- Migrate stored configs: upgrade legacy bare ids to backend-prefixed form on read.
- Validate the shape when saving provider config, not only when generating.
When it happens
Trigger: A stored provider config `model` value like `seed-tts-2.0` (no backend prefix) — from manual config edits, older formats, or a server catalog entry missing its prefix; user typing a custom model id directly into the picker; a backend rename that dropped the prefix from returned catalog entries.
Common situations: Migrating stored settings from an older version that stored bare resource ids; hand-editing provider config files; a server catalog regression listing resource-only ids; copy-pasting model names from Volcengine docs without the backend namespace.
Related errors
- No streaming TTS model selected and server returned no defau
- [Speech Pipeline] bidirectional-ws provider reached per-segm
- MiMo TTS response missing audio data
- MiniMax TTS request failed: ${response.status} ${response.st
- OpenRouter audio request failed: ${response.status} ${await
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/7c0c8be4d0ba2b6d.
Report an issue: GitHub.