sipeed/picoclaw · error
invalid TTS response: missing audio data
Error message
invalid TTS response: missing audio data
What it means
Returned when the MiMo endpoint returns HTTP 200 with valid JSON but choices is empty or choices[0].message.audio.data is empty. The model answered as chat text instead of synthesizing audio — typically a non-TTS model name, a voice the endpoint silently rejects, or moderation refusing to vocalize the input.
Source
Thrown at pkg/audio/tts/mimo_tts.go:153
}
var payload struct {
Choices []struct {
Message struct {
Audio struct {
Data string `json:"data"`
} `json:"audio"`
} `json:"message"`
} `json:"choices"`
}
err = json.Unmarshal(body, &payload)
if err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
if len(payload.Choices) == 0 || payload.Choices[0].Message.Audio.Data == "" {
return nil, fmt.Errorf("invalid TTS response: missing audio data")
}
audioBytes, err := base64.StdEncoding.DecodeString(payload.Choices[0].Message.Audio.Data)
if err != nil {
return nil, fmt.Errorf("failed to decode audio data: %w", err)
}
return io.NopCloser(bytes.NewReader(audioBytes)), nil
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Set the model explicitly to mimo-v2-tts
- Keep the default voice default_zh unless the provider documents alternatives
- Smoke-test a short plain 'hello' synthesis; if that fails it is model/voice config, not the input
- Fall back to the OpenAI TTS provider — SynthesizeAndStore accepts any TTSProvider
Example fix
// before p := tts.NewMimoTTSProvider(key, base, `mimo-v2`, ``) // text model: no audio // after p := tts.NewMimoTTSProvider(key, base, `mimo-v2-tts`, ``)
Defensive patterns
Strategy: fallback
Type guard
func isMissingAudio(err error) bool {
return err != nil && strings.Contains(err.Error(), `missing audio data`)
} Try / catch
if isMissingAudio(err) && openaiProvider != nil {
// mimo answered without audio (model/voice config): fall back to another TTSProvider
stream, err = openaiProvider.Synthesize(ctx, text)
} Prevention
- Use mimo-v2-tts, never the text model, for synthesis
- Keep voice default_zh unless the provider documents alternatives
- Smoke-test a short 'hello' synthesis after every model config change
When it happens
Trigger: Model set to a text-only model (e.g. 'mimo-v2') instead of 'mimo-v2-tts'; a voice value the endpoint does not map to audio (the code pins default_zh because mimo_default resolves to default_en); content moderation on the input text.
Common situations: Guessing model names in config; provider changing default voice aliases (noted in the code comment); inputs with characters the TTS refuses.
Related errors
- API error (status %d): %s
- failed to decode response: %w
- failed to send request: %w
- failed to read response: %w
- failed to decode audio data: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/0bc79d683d0868f5.
Report an issue: GitHub.