chenhg5/cc-connect · error
mimo tts: decode audio base64: %w
Error message
mimo tts: decode audio base64: %w
What it means
MiMoTTS.Synthesize received a 200 response whose chat-completion message contains an audio.data field that is present but not valid standard base64. The library base64-decodes the returned audio payload into WAV bytes, and Go's base64.StdEncoding.DecodeString rejected it. This almost always means the endpoint returned something unexpected in the audio field (HTML/JSON error text, URL-safe or unpadded base64, or whitespace-corrupted data) rather than properly encoded audio.
Source
Thrown at core/tts.go:522
Error *struct {
Message string `json:"message"`
Type string `json:"type"`
Code any `json:"code"`
} `json:"error"`
}
if err := json.Unmarshal(body, &result); err != nil {
return nil, "", fmt.Errorf("mimo tts: parse response: %w", err)
}
if result.Error != nil && result.Error.Message != "" {
return nil, "", fmt.Errorf("mimo tts API error: %s", result.Error.Message)
}
if len(result.Choices) == 0 || result.Choices[0].Message.Audio.Data == "" {
return nil, "", fmt.Errorf("mimo tts: empty audio data in response")
}
audio, err := base64.StdEncoding.DecodeString(result.Choices[0].Message.Audio.Data)
if err != nil {
return nil, "", fmt.Errorf("mimo tts: decode audio base64: %w", err)
}
return audio, "wav", nil
}
// ──────────────────────────────────────────────────────────────
// EspeakTTS — Local eSpeak text-to-speech implementation
// ──────────────────────────────────────────────────────────────
// EspeakTTS implements TextToSpeech using the local espeak command.
type EspeakTTS struct {
Path string // path to espeak executable (empty = "espeak")
Voice string // default voice (e.g. "zh", "en", "zh+f3")
}
// NewEspeakTTS creates a new EspeakTTS instance.
func NewEspeakTTS(path, voice string) *EspeakTTS {
if path == "" {
path = "espeak"View on GitHub (pinned to 4000b2338a)
Solutions
- Log a prefix of result.Choices[0].Message.Audio.Data (first ~100 chars) before decoding to see what was actually returned.
- Check that BaseURL points to the real MiMo audio-capable endpoint and that the API key/model supports TTS audio output.
- Trim whitespace/newlines and retry with base64.RawStdEncoding.DecodeString in case the payload is raw/unpadded base64.
- Confirm the configured model actually emits audio; some compat endpoints return text-only 200 responses for unsupported models.
Example fix
// before
audio, err := base64.StdEncoding.DecodeString(result.Choices[0].Message.Audio.Data)
if err != nil {
return nil, "", fmt.Errorf("mimo tts: decode audio base64: %w", err)
}
// after
payload := strings.Map(func(r rune) rune {
if r == '\n' || r == '\r' || r == ' ' { return -1 }
return r
}, result.Choices[0].Message.Audio.Data)
audio, err := base64.StdEncoding.DecodeString(payload)
if err != nil {
audio, err = base64.RawStdEncoding.DecodeString(payload)
}
if err != nil {
return nil, "", fmt.Errorf("mimo tts: decode audio base64 (len=%d): %w", len(payload), err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: sanity-check input before calling Synthesize
if strings.TrimSpace(text) == "" { return errors.New("text required") }
// After the call, inspect the wrapped cause:
var bad base64.CorruptInputError
if errors.As(err, &bad) { /* payload was not valid std base64 -> inspect provider response */ } Type guard
func isBase64Std(s string) bool {
if s == "" { return false }
_, err := base64.StdEncoding.DecodeString(s)
return err == nil
} Try / catch
audio, format, err := tts.Synthesize(ctx, text, opts)
if err != nil {
if strings.Contains(err.Error(), "decode audio base64") {
log.Printf("provider returned non-base64 audio payload; verify endpoint/model")
// fall back to another TTS engine or surface a config error
return fallbackTTS.Synthesize(ctx, text, opts)
}
return fmt.Errorf("tts synthesize: %w", err)
} Prevention
- Pin BaseURL/model to an endpoint verified to return inline base64 audio for TTS.
- Log the raw audio.data prefix on failure to catch provider-side format changes early.
- Integration-test the decode path to detect API drift before production.
- Handle unpadded/URL-safe base64 variants defensively before failing.
When it happens
Trigger: Calling Synthesize via MiMoTTS when the API responds HTTP 200 but choices[0].message.audio.data contains characters outside the standard base64 alphabet, has incorrect padding, or contains whitespace/quotes — e.g. the provider silently downgraded the request or returned a URL/error page instead of inline audio.
Common situations: BaseURL pointed at an OpenAI-compatible proxy that doesn't support the audio modality; an API version change on the MiMo/compat endpoint altering payload encoding; a gateway returning a canned 200 HTML page; the base64 string passing through a layer that URL-encodes or line-wraps it.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- platform %s does not support audio sending
- synthesize: %w
- qwen tts: empty audio URL in response
- dingtalk: send audio failed: status=%d, body=%s
- tts is not configured
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/bb9d502321207166.
Report an issue: GitHub.