{"record":{"id":"e80a7111688880bc","repo":"chenhg5/cc-connect","slug":"ffmpeg-conversion-failed-w-stderr-s","errorCode":null,"errorMessage":"ffmpeg conversion failed: %w (stderr: %s)","messagePattern":"ffmpeg conversion failed: %w \\(stderr: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/speech.go","lineNumber":337,"sourceCode":"\t\t)\n\t} else {\n\t\tcmd = exec.CommandContext(ctx, ffmpegPath,\n\t\t\t\"-i\", \"pipe:0\",\n\t\t\t\"-f\", \"mp3\",\n\t\t\t\"-ac\", \"1\",\n\t\t\t\"-ar\", \"16000\",\n\t\t\t\"-y\",\n\t\t\t\"pipe:1\",\n\t\t)\n\t}\n\n\tcmd.Stdin = bytes.NewReader(audio)\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 conversion failed: %w (stderr: %s)\", err, stderr.String())\n\t}\n\treturn stdout.Bytes(), nil\n}\n\n// ConvertAudioToOpus uses ffmpeg to convert audio to opus format (ogg container).\n// Returns the opus bytes. If ffmpeg is not installed, returns an error.\nfunc ConvertAudioToOpus(ctx context.Context, audio []byte, srcFormat string) ([]byte, error) {\n\tffmpegPath, err := exec.LookPath(\"ffmpeg\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ffmpeg not found in PATH: install ffmpeg to enable audio conversion\")\n\t}\n\n\targs := []string{\"-i\", \"pipe:0\", \"-c:a\", \"libopus\", \"-f\", \"opus\", \"-y\", \"pipe:1\"}\n\tif srcFormat == \"amr\" || srcFormat == \"silk\" {\n\t\targs = append([]string{\"-f\", srcFormat}, args...)\n\t}\n\tcmd := exec.CommandContext(ctx, ffmpegPath, args...)\n\tcmd.Stdin = bytes.NewReader(audio)","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/speech.go#L319-L355","documentation":"ConvertAudioToMP3 pipes the audio into an ffmpeg subprocess and captures its stderr. When cmd.Run() returns an error — ffmpeg exited non-zero or could not be started — the error is wrapped with the captured stderr so the developer can see ffmpeg's own diagnostic output. This means the input audio was rejected or ffmpeg itself failed, not that ffmpeg is missing (that is a separate error).","triggerScenarios":"Calling ConvertAudioToMP3 with bytes that ffmpeg cannot decode (corrupt/truncated upload, wrong srcFormat such as claiming \"silk\" for mp3 data, unsupported codec), an empty audio buffer, or the ctx being cancelled mid-conversion (cancellation kills the subprocess and surfaces as a signal/killed error).","commonSituations":"A messaging platform delivers a voice file whose actual codec differs from the declared format; a user sends a zero-byte or partially downloaded file; the context deadline expires on a slow conversion; the installed ffmpeg build lacks a decoder for the source codec.","solutions":["Read the stderr portion of the error — it contains ffmpeg's exact complaint (unknown format, invalid data, etc.) and fix the input accordingly.","Verify srcFormat matches the actual container/codec of the bytes (e.g. inspect the first bytes or the platform's mime type).","If the error is a context cancellation/deadline, increase the timeout or investigate why conversion is slow.","Re-fetch the audio from the platform if the download may have been truncated, and reject empty buffers before calling."],"exampleFix":"// before\nmp3, err := core.ConvertAudioToMP3(ctx, data, \"silk\")\n// after\nif len(data) == 0 {\n    return fmt.Errorf(\"empty audio payload\")\n}\nformat := detectFormat(mimeType) // e.g. from Content-Type header\nmp3, err := core.ConvertAudioToMP3(ctx, data, format)","handlingStrategy":"try-catch","validationCode":"if len(audio) == 0 {\n    return fmt.Errorf(\"empty audio payload\")\n}\n","typeGuard":null,"tryCatchPattern":"mp3, err := core.ConvertAudioToMP3(ctx, audio, srcFormat)\nif err != nil {\n    var exitErr *exec.ExitError\n    if errors.As(err, &exitErr) {\n        log.Error(\"ffmpeg failed\", \"stderr\", extractStderr(err))\n    }\n    if ctx.Err() != nil {\n        return fmt.Errorf(\"conversion cancelled: %w\", ctx.Err())\n    }\n    return fmt.Errorf(\"convert audio: %w\", err)\n}","preventionTips":["Derive srcFormat from the platform's mime type / file header instead of trusting filename extensions.","Reject empty or suspiciously small payloads before conversion.","Give the conversion context a generous but bounded timeout.","Keep ffmpeg updated so source codecs are decodable; check stderr on every failure — it names the exact problem."],"tags":["ffmpeg","audio","subprocess","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"}