{"record":{"id":"1d5d0af33d90a4f6","repo":"chenhg5/cc-connect","slug":"openai-tts-read-audio-w","errorCode":null,"errorMessage":"openai tts: read audio: %w","messagePattern":"openai tts: read audio: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tts.go","lineNumber":268,"sourceCode":"\t\treturn nil, \"\", fmt.Errorf(\"openai tts: create request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+o.APIKey)\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tresp, err := o.Client.Do(req)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"openai tts: request: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tbody, _ := io.ReadAll(resp.Body)\n\t\treturn nil, \"\", fmt.Errorf(\"openai tts API %d: %s\", resp.StatusCode, body)\n\t}\n\n\tmp3Data, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"openai tts: read audio: %w\", err)\n\t}\n\treturn mp3Data, \"mp3\", nil\n}\n\n// ──────────────────────────────────────────────────────────────\n// MiniMaxTTS — MiniMax T2A v2 TTS implementation\n// ──────────────────────────────────────────────────────────────\n\n// MiniMaxTTS implements TextToSpeech using the MiniMax T2A v2 API.\ntype MiniMaxTTS struct {\n\tAPIKey  string\n\tBaseURL string\n\tModel   string\n\tClient  *http.Client\n}\n\n// NewMiniMaxTTS creates a new MiniMaxTTS instance.\nfunc NewMiniMaxTTS(apiKey, baseURL, model string, client *http.Client) *MiniMaxTTS {","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/tts.go#L250-L286","documentation":"This error is returned when io.ReadAll fails while streaming the successful (200) TTS response body into memory as MP3 bytes. It indicates the connection was interrupted or reset mid-download of the audio payload, not an API rejection.","triggerScenarios":"Server or proxy closes the connection partway through the audio body, TLS truncation, network drop during transfer, or an intermediary killing long-lived responses.","commonSituations":"Flaky mobile/VPN connections, aggressive load balancers with short idle/response timeouts, large speech outputs over unstable links.","solutions":["Retry the Synthesize call — transient truncation usually succeeds on retry","Check for proxies/load balancers with short response timeouts between client and endpoint","Add retry-with-backoff around Synthesize in the caller","Ensure the http.Client has sane timeouts that don't cut off slow audio transfers"],"exampleFix":"// before\nmp3, format, err := tts.Synthesize(ctx, text)\nif err != nil { return err } // one shot, no retry\n// after\nmp3, format, err := synthesizeWithRetry(ctx, tts, text, 3) // backoff retries\nif err != nil { return fmt.Errorf(\"tts synthesize: %w\", err) }","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"var mp3 []byte\nvar err error\nfor attempt := 0; attempt < 3; attempt++ {\n    mp3, _, err = tts.Synthesize(ctx, text)\n    if err == nil || !strings.Contains(err.Error(), \"read audio\") { break }\n    time.Sleep(time.Duration(attempt+1) * time.Second)\n}","preventionTips":["Wrap Synthesize in bounded retry with backoff","Check intermediary proxies/load balancers for short response-timeout settings","Avoid synthesizing very long texts in a single call; chunk if needed"],"tags":["go","tts","io","network"],"backgroundTag":"network-request-failed","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"}