chenhg5/cc-connect · error

ffmpeg compression failed: %w (stderr: %s)

Error message

ffmpeg compression failed: %w (stderr: %s)

What it means

ffmpeg itself was found and started but exited with a non-zero status while transcoding the WAV input to 16kHz mono 64kbps MP3. The error wraps ffmpeg's exit error plus the process stderr, which contains ffmpeg's own diagnostic (bad input, unsupported codec, etc.).

Source

Thrown at platform/dingtalk/dingtalk.go:1331

	}

	args := []string{
		"-i", "pipe:0",
		"-ar", "16000", // 16kHz sample rate for voice
		"-ac", "1", // mono
		"-b:a", "64k", // 64 kbps bitrate (voice quality)
		"-f", "mp3",
		"-y",
		"pipe:1",
	}
	cmd := exec.CommandContext(ctx, ffmpegPath, args...)
	cmd.Stdin = bytes.NewReader(audio)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		return nil, "", fmt.Errorf("ffmpeg compression failed: %w (stderr: %s)", err, stderr.String())
	}

	return stdout.Bytes(), "mp3", nil
}

// uploadMedia uploads a file to DingTalk media API and returns the media ID.
// mediaType should be "voice" or "image".
func (p *Platform) uploadMedia(ctx context.Context, data []byte, fileName, mediaType string) (string, error) {
	token, err := p.getAccessToken()
	if err != nil {
		return "", fmt.Errorf("get access token: %w", err)
	}

	uploadURL := fmt.Sprintf("https://oapi.dingtalk.com/media/upload?access_token=%s&type=%s", token, mediaType)

	body := bytes.NewBuffer(nil)
	writer := multipart.NewWriter(body)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Inspect the stderr suffix in the error — it names the real cause (e.g. "Invalid data", "Unknown encoder 'libmp3lame'").
  2. Install a full ffmpeg build with libmp3lame (e.g. ffmpeg-full).
  3. Validate/repair the source WAV before compressing (check header, RIFF size, non-zero length).
  4. Retry once for transient failures (killed process, interrupted I/O).

Example fix

// before: passing truncated audio
audio := buf.Bytes() // buf may be incomplete after context cancel
// after
if len(audio) == 0 || !bytes.HasPrefix(audio, []byte("RIFF")) {
    return errors.New("invalid WAV payload")
}
out, format, err := p.compressAudio(ctx, audio, "wav")
Defensive patterns

Strategy: validation

Validate before calling

func looksLikeWav(b []byte) bool { return len(b) > 44 && bytes.HasPrefix(b, []byte("RIFF")) && bytes.Contains(b[:12], []byte("WAVE")) }
if !looksLikeWav(audio) { return errors.New("invalid or truncated WAV input") }

Try / catch

out, format, err := p.compressAudio(ctx, audio, "wav")
if err != nil {
    slog.Warn("ffmpeg transcode failed", "stderr", extractStderr(err))
    return err // surface stderr to user diagnostics
}

Prevention

When it happens

Trigger: cmd.Run() returns an error during compressAudioWithFFmpeg — e.g. the stdin bytes are not a valid WAV stream, the file is truncated/corrupt, or the installed ffmpeg build lacks the MP3 (libmp3lame) encoder.

Common situations: Upstream TTS produced truncated audio (partial write/cancelled context); a minimal ffmpeg build compiled without libmp3lame; input mislabeled as WAV but actually another codec; OOM kill of the ffmpeg process.

Related errors


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