{"record":{"id":"2e45083ef11fcb06","repo":"chenhg5/cc-connect","slug":"ffmpeg-mp3-to-ogg-conversion-failed-w-stderr","errorCode":null,"errorMessage":"ffmpeg MP3 to OGG conversion failed: %w (stderr: %s)","messagePattern":"ffmpeg MP3 to OGG conversion failed: %w \\(stderr: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/speech.go","lineNumber":426,"sourceCode":"\targs := []string{\n\t\t\"-i\", \"pipe:0\",\n\t\t\"-c:a\", \"libopus\",\n\t\t\"-ar\", \"16000\",       // 16kHz sample rate for voice\n\t\t\"-ac\", \"1\",           // mono\n\t\t\"-b:a\", \"32k\",        // 32 kbps bitrate (voice quality)\n\t\t\"-application\", \"voip\", // optimize for voice\n\t\t\"-f\", \"ogg\",\n\t\t\"-y\",\n\t\t\"pipe:1\",\n\t}\n\tcmd := exec.CommandContext(ctx, ffmpegPath, args...)\n\tcmd.Stdin = bytes.NewReader(mp3Data)\n\tvar stdout, stderr bytes.Buffer\n\tcmd.Stdout = &stdout\n\tcmd.Stderr = &stderr\n\n\tif err := cmd.Run(); err != nil {\n\t\treturn nil, fmt.Errorf(\"ffmpeg MP3 to OGG conversion failed: %w (stderr: %s)\", err, stderr.String())\n\t}\n\treturn stdout.Bytes(), nil\n}\n\n// ConvertMP3ToAMR converts MP3 audio to AMR format using ffmpeg with stdin/stdout pipes.\n// AMR format is smaller but lower quality than OGG (AMR-NB codec, 8kHz mono, 12.2kbps).\nfunc ConvertMP3ToAMR(ctx context.Context, mp3Data []byte) ([]byte, error) {\n\tffmpegPath, err := exec.LookPath(\"ffmpeg\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ffmpeg not found in PATH: %w\", err)\n\t}\n\n\targs := []string{\n\t\t\"-i\", \"pipe:0\",\n\t\t\"-c:a\", \"amr_nb\",\n\t\t\"-ar\", \"8000\",     // 8kHz sample rate (AMR-NB standard)\n\t\t\"-ac\", \"1\",        // mono\n\t\t\"-b:a\", \"12.2k\",   // 12.2 kbps bitrate (AMR-NB max)","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/speech.go#L408-L444","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nogg, err := core.ConvertMP3ToOGG(ctx, raw)\n// after\nif len(raw) < 4 || !(bytes.HasPrefix(raw, []byte(\"ID3\")) || raw[0] == 0xFF) {\n    return fmt.Errorf(\"payload is not MP3\")\n}\nogg, err := core.ConvertMP3ToOGG(ctx, raw)","handlingStrategy":"try-catch","validationCode":"if len(mp3) < 4 || !(bytes.HasPrefix(mp3, []byte(\"ID3\")) || mp3[0] == 0xFF) {\n    return fmt.Errorf(\"payload is not MP3\")\n}\n","typeGuard":null,"tryCatchPattern":"ogg, err := core.ConvertMP3ToOGG(ctx, mp3Data)\nif err != nil {\n    log.Error(\"mp3->ogg failed\", \"stderr\", extractStderr(err))\n    if ctx.Err() != nil {\n        return fmt.Errorf(\"conversion timed out: %w\", ctx.Err())\n    }\n    return fmt.Errorf(\"voice conversion: %w\", err)\n}","preventionTips":["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."],"tags":["ffmpeg","audio","subprocess","ogg","conversion-failed"],"backgroundTag":"ffmpeg-conversion-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}