{"record":{"id":"bb9d502321207166","repo":"chenhg5/cc-connect","slug":"mimo-tts-decode-audio-base64-w","errorCode":null,"errorMessage":"mimo tts: decode audio base64: %w","messagePattern":"mimo tts: decode audio base64: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tts.go","lineNumber":522,"sourceCode":"\t\tError *struct {\n\t\t\tMessage string `json:\"message\"`\n\t\t\tType    string `json:\"type\"`\n\t\t\tCode    any    `json:\"code\"`\n\t\t} `json:\"error\"`\n\t}\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"mimo tts: parse response: %w\", err)\n\t}\n\tif result.Error != nil && result.Error.Message != \"\" {\n\t\treturn nil, \"\", fmt.Errorf(\"mimo tts API error: %s\", result.Error.Message)\n\t}\n\tif len(result.Choices) == 0 || result.Choices[0].Message.Audio.Data == \"\" {\n\t\treturn nil, \"\", fmt.Errorf(\"mimo tts: empty audio data in response\")\n\t}\n\n\taudio, err := base64.StdEncoding.DecodeString(result.Choices[0].Message.Audio.Data)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"mimo tts: decode audio base64: %w\", err)\n\t}\n\treturn audio, \"wav\", nil\n}\n\n// ──────────────────────────────────────────────────────────────\n// EspeakTTS — Local eSpeak text-to-speech implementation\n// ──────────────────────────────────────────────────────────────\n\n// EspeakTTS implements TextToSpeech using the local espeak command.\ntype EspeakTTS struct {\n\tPath  string // path to espeak executable (empty = \"espeak\")\n\tVoice string // default voice (e.g. \"zh\", \"en\", \"zh+f3\")\n}\n\n// NewEspeakTTS creates a new EspeakTTS instance.\nfunc NewEspeakTTS(path, voice string) *EspeakTTS {\n\tif path == \"\" {\n\t\tpath = \"espeak\"","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/tts.go#L504-L540","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\naudio, err := base64.StdEncoding.DecodeString(result.Choices[0].Message.Audio.Data)\nif err != nil {\n\treturn nil, \"\", fmt.Errorf(\"mimo tts: decode audio base64: %w\", err)\n}\n// after\npayload := strings.Map(func(r rune) rune {\n\tif r == '\\n' || r == '\\r' || r == ' ' { return -1 }\n\treturn r\n}, result.Choices[0].Message.Audio.Data)\naudio, err := base64.StdEncoding.DecodeString(payload)\nif err != nil {\n\taudio, err = base64.RawStdEncoding.DecodeString(payload)\n}\nif err != nil {\n\treturn nil, \"\", fmt.Errorf(\"mimo tts: decode audio base64 (len=%d): %w\", len(payload), err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: sanity-check input before calling Synthesize\nif strings.TrimSpace(text) == \"\" { return errors.New(\"text required\") }\n// After the call, inspect the wrapped cause:\nvar bad base64.CorruptInputError\nif errors.As(err, &bad) { /* payload was not valid std base64 -> inspect provider response */ }","typeGuard":"func isBase64Std(s string) bool {\n\tif s == \"\" { return false }\n\t_, err := base64.StdEncoding.DecodeString(s)\n\treturn err == nil\n}","tryCatchPattern":"audio, format, err := tts.Synthesize(ctx, text, opts)\nif err != nil {\n\tif strings.Contains(err.Error(), \"decode audio base64\") {\n\t\tlog.Printf(\"provider returned non-base64 audio payload; verify endpoint/model\")\n\t\t// fall back to another TTS engine or surface a config error\n\t\treturn fallbackTTS.Synthesize(ctx, text, opts)\n\t}\n\treturn fmt.Errorf(\"tts synthesize: %w\", err)\n}","preventionTips":["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."],"tags":["tts","base64","api-response","audio"],"backgroundTag":"invalid-json-response","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}