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

  1. Log a prefix of result.Choices[0].Message.Audio.Data (first ~100 chars) before decoding to see what was actually returned.
  2. Check that BaseURL points to the real MiMo audio-capable endpoint and that the API key/model supports TTS audio output.
  3. Trim whitespace/newlines and retry with base64.RawStdEncoding.DecodeString in case the payload is raw/unpadded base64.
  4. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/bb9d502321207166. Report an issue: GitHub.