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

  1. Verify the text passed to Synthesize is non-empty after trimming; guard at the call site
  2. 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
  3. Upgrade edge-tts (`pip install -U edge-tts`) — newer versions correctly fail non-zero on service errors instead of writing empty files
  4. 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

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


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