{"record":{"id":"953688285c272e36","repo":"chenhg5/cc-connect","slug":"edge-tts-produced-empty-audio-file","errorCode":null,"errorMessage":"edge-tts: produced empty audio file","messagePattern":"edge-tts: produced empty audio file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tts.go","lineNumber":719,"sourceCode":"\n\tpath := e.Path\n\tif path == \"\" {\n\t\tpath = \"edge-tts\"\n\t}\n\tcmd := exec.CommandContext(ctx, path, args...)\n\toutput, err := cmd.CombinedOutput()\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"edge-tts: voice=%s text=%q: %w, output: %s\", voice, text, err, string(output))\n\t}\n\n\t// Read the generated MP3 file\n\taudioData, err := os.ReadFile(tmpPath)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"edge-tts: read output file: %w\", err)\n\t}\n\n\tif len(audioData) == 0 {\n\t\treturn nil, \"\", fmt.Errorf(\"edge-tts: produced empty audio file\")\n\t}\n\n\treturn audioData, \"mp3\", nil\n}\n","sourceCodeStart":701,"sourceCodeEnd":724,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/tts.go#L701-L724","documentation":"EdgeTTS.Synthesize (core/tts.go:719) returns this error when the edge-tts CLI exited 0 but the MP3 file it was asked to write via --write-media is zero bytes. The library refuses to return empty audio, treating it as a failed synthesis. It typically means the CLI swallowed a real failure (network or auth) and still exited successfully.","triggerScenarios":"Calling EdgeTTS.Synthesize when edge-tts completes without error but writes an empty file — e.g. empty or whitespace-only --text input, an edge-tts version that exits 0 on service auth errors without writing media, or the connection to Microsoft's service dropped before any audio bytes were flushed to disk.","commonSituations":"Flaky networks or proxies where the connection drops mid-request but edge-tts still exits 0; text preprocessing upstream that produces empty strings; outdated edge-tts versions with broken token refresh silently producing nothing.","solutions":["Verify the text passed to Synthesize is non-empty after trimming; guard at the call site","Run `edge-tts --voice zh-CN-XiaoxiaoNeural --text 'test' --write-media /tmp/t.mp3` manually and check the file size to reproduce outside the library","Upgrade edge-tts (`pip install -U edge-tts`) — newer versions correctly fail non-zero on service errors instead of writing empty files","Implement a retry with fallback to another TTS backend for transient empty outputs"],"exampleFix":"// before\ntext := extractTextFromMessage(msg)\naudio, _, err := edge.Synthesize(ctx, text, opts)\n// after\ntext := strings.TrimSpace(extractTextFromMessage(msg))\nif text == \"\" {\n    return errors.New(\"nothing to speak\")\n}\naudio, _, err := edge.Synthesize(ctx, text, opts)","handlingStrategy":"validation","validationCode":"text = strings.TrimSpace(text)\nif text == \"\" {\n    return errors.New(\"refusing to synthesize empty text\")\n}\nif _, err := exec.LookPath(\"edge-tts\"); err != nil {\n    return errors.New(\"edge-tts CLI not installed\")\n}","typeGuard":"func hasAudio(b []byte) bool {\n    return len(b) > 0 && (bytes.HasPrefix(b, []byte(\"ID3\")) || b[0] == 0xFF)\n}","tryCatchPattern":"audio, format, err := edge.Synthesize(ctx, text, opts)\nif err != nil && strings.Contains(err.Error(), \"produced empty audio file\") {\n    slog.Warn(\"edge-tts wrote empty mp3, falling back to pico2wave\")\n    audio, format, err = pico.Synthesize(ctx, text, opts)\n    if err != nil {\n        return fmt.Errorf(\"all tts backends failed: %w\", err)\n    }\n}","preventionTips":["Guard against empty/whitespace text before every Synthesize call","Upgrade edge-tts so service errors surface as non-zero exits rather than empty files","Verify edge-tts works with a manual CLI run when configuring a new voice","Add a retry-then-fallback chain across TTS backends for transient empty outputs"],"tags":["tts","edge-tts","external-cli","empty-output"],"backgroundTag":"empty-api-response","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}