chenhg5/cc-connect · error
edge-tts: produced empty audio file
Error message
edge-tts: produced empty audio file
What it means
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.
Source
Thrown at core/tts.go:719
path := e.Path
if path == "" {
path = "edge-tts"
}
cmd := exec.CommandContext(ctx, path, args...)
output, err := cmd.CombinedOutput()
if err != nil {
return nil, "", fmt.Errorf("edge-tts: voice=%s text=%q: %w, output: %s", voice, text, err, string(output))
}
// Read the generated MP3 file
audioData, err := os.ReadFile(tmpPath)
if err != nil {
return nil, "", fmt.Errorf("edge-tts: read output file: %w", err)
}
if len(audioData) == 0 {
return nil, "", fmt.Errorf("edge-tts: produced empty audio file")
}
return audioData, "mp3", nil
}
View on GitHub (pinned to 4000b2338a)
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
Example fix
// before
text := extractTextFromMessage(msg)
audio, _, err := edge.Synthesize(ctx, text, opts)
// after
text := strings.TrimSpace(extractTextFromMessage(msg))
if text == "" {
return errors.New("nothing to speak")
}
audio, _, err := edge.Synthesize(ctx, text, opts) Defensive patterns
Strategy: validation
Validate before calling
text = strings.TrimSpace(text)
if text == "" {
return errors.New("refusing to synthesize empty text")
}
if _, err := exec.LookPath("edge-tts"); err != nil {
return errors.New("edge-tts CLI not installed")
} Type guard
func hasAudio(b []byte) bool {
return len(b) > 0 && (bytes.HasPrefix(b, []byte("ID3")) || b[0] == 0xFF)
} Try / catch
audio, format, err := edge.Synthesize(ctx, text, opts)
if err != nil && strings.Contains(err.Error(), "produced empty audio file") {
slog.Warn("edge-tts wrote empty mp3, falling back to pico2wave")
audio, format, err = pico.Synthesize(ctx, text, opts)
if err != nil {
return fmt.Errorf("all tts backends failed: %w", err)
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.
Related errors
- pico2wave: produced empty audio file
- edge-tts: voice=%s text=%q: %w, output: %s
- edge-tts: create temp file: %w
- edge-tts: read output file: %w
- tts is not configured
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/953688285c272e36.
Report an issue: GitHub.