chenhg5/cc-connect · error
ffmpeg MP3 to OGG conversion failed: %w (stderr: %s)
Error message
ffmpeg MP3 to OGG conversion failed: %w (stderr: %s)
What it means
ConvertMP3ToOGG feeds MP3 bytes to ffmpeg over stdin and reads OGG from stdout; when cmd.Run() returns an error the library wraps it with the captured stderr. This indicates ffmpeg executed but rejected the job — typically undecodable MP3 data or an ffmpeg build lacking the libopus encoder. It is distinct from the missing-binary error raised earlier in the same function.
Source
Thrown at core/speech.go:426
args := []string{
"-i", "pipe:0",
"-c:a", "libopus",
"-ar", "16000", // 16kHz sample rate for voice
"-ac", "1", // mono
"-b:a", "32k", // 32 kbps bitrate (voice quality)
"-application", "voip", // optimize for voice
"-f", "ogg",
"-y",
"pipe:1",
}
cmd := exec.CommandContext(ctx, ffmpegPath, args...)
cmd.Stdin = bytes.NewReader(mp3Data)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("ffmpeg MP3 to OGG conversion failed: %w (stderr: %s)", err, stderr.String())
}
return stdout.Bytes(), nil
}
// ConvertMP3ToAMR converts MP3 audio to AMR format using ffmpeg with stdin/stdout pipes.
// AMR format is smaller but lower quality than OGG (AMR-NB codec, 8kHz mono, 12.2kbps).
func ConvertMP3ToAMR(ctx context.Context, mp3Data []byte) ([]byte, error) {
ffmpegPath, err := exec.LookPath("ffmpeg")
if err != nil {
return nil, fmt.Errorf("ffmpeg not found in PATH: %w", err)
}
args := []string{
"-i", "pipe:0",
"-c:a", "amr_nb",
"-ar", "8000", // 8kHz sample rate (AMR-NB standard)
"-ac", "1", // mono
"-b:a", "12.2k", // 12.2 kbps bitrate (AMR-NB max)View on GitHub (pinned to 4000b2338a)
Solutions
- Read the stderr suffix of the error — ffmpeg names the exact problem (Invalid data, Unknown encoder 'libopus').
- For missing libopus, install a full-featured ffmpeg build.
- Validate the payload is real MP3 (check for the ID3/0xFFFB sync header) before converting.
- If cancellation-related, increase the conversion timeout or run it earlier in the pipeline.
Example fix
// before
ogg, err := core.ConvertMP3ToOGG(ctx, raw)
// after
if len(raw) < 4 || !(bytes.HasPrefix(raw, []byte("ID3")) || raw[0] == 0xFF) {
return fmt.Errorf("payload is not MP3")
}
ogg, err := core.ConvertMP3ToOGG(ctx, raw) Defensive patterns
Strategy: try-catch
Validate before calling
if len(mp3) < 4 || !(bytes.HasPrefix(mp3, []byte("ID3")) || mp3[0] == 0xFF) {
return fmt.Errorf("payload is not MP3")
}
Try / catch
ogg, err := core.ConvertMP3ToOGG(ctx, mp3Data)
if err != nil {
log.Error("mp3->ogg failed", "stderr", extractStderr(err))
if ctx.Err() != nil {
return fmt.Errorf("conversion timed out: %w", ctx.Err())
}
return fmt.Errorf("voice conversion: %w", err)
} Prevention
- Verify MP3 magic bytes before conversion rather than trusting file names.
- Install full ffmpeg builds that include libopus.
- Re-download audio when file sizes look truncated.
- Capture and log stderr on every conversion failure for fast diagnosis.
When it happens
Trigger: SendAudio (or a direct call) passes non-MP3 bytes, corrupt/truncated MP3s, an empty slice, or ctx is cancelled during conversion; also when the installed ffmpeg has no libopus encoder.
Common situations: A platform's voice download actually returns another container despite a .mp3 name; partially downloaded files; minimal ffmpeg distributions (e.g. some static builds ship without libopus); timeouts killing long conversions.
Related errors
- ffmpeg conversion failed: %w (stderr: %s)
- ffmpeg opus conversion failed: %w (stderr: %s)
- ffmpeg AMR conversion failed: %w (stderr: %s)
- ffmpeg MP3 to AMR conversion failed: %w (stderr: %s)
- ffmpeg not found in PATH: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/2e45083ef11fcb06.
Report an issue: GitHub.