{"record":{"id":"d7903e5ce6aa0322","repo":"chenhg5/cc-connect","slug":"ffmpeg-amr-conversion-failed-w-stderr-s","errorCode":null,"errorMessage":"ffmpeg AMR conversion failed: %w (stderr: %s)","messagePattern":"ffmpeg AMR conversion failed: %w \\(stderr: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/speech.go","lineNumber":395,"sourceCode":"\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)\n\t\t\"-f\", \"amr\",\n\t\t\"-y\",\n\t\t\"pipe:1\",\n\t}\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)\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 AMR conversion failed: %w (stderr: %s)\", err, stderr.String())\n\t}\n\treturn stdout.Bytes(), nil\n}\n\n// ConvertMP3ToOGG converts MP3 audio to OGG format using ffmpeg with stdin/stdout pipes.\n// Optimized for voice: Opus codec, 16kHz mono, 32kbps, voip application.\nfunc ConvertMP3ToOGG(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\", \"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)","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/speech.go#L377-L413","documentation":"ConvertAudioToAMR shells out to ffmpeg; when cmd.Run() fails it wraps the error along with the captured stderr buffer. This signals that ffmpeg ran but the AMR conversion itself failed — the wrapper text differs per converter (\"AMR conversion failed\") so callers can tell which stage broke. The stderr content is ffmpeg's own error output and is the primary diagnostic.","triggerScenarios":"SendAudio (or a direct call) supplies bytes that cannot be decoded to AMR-NB: input already at a sample rate/codec ffmpeg refuses for amr_nb without resampling context, empty buffer, srcFormat mismatch (declared \"silk\" but actually mp3), missing amr_nb encoder in the ffmpeg build, or ctx cancellation terminating the process.","commonSituations":"Minimal ffmpeg builds without native AMR encoder; voice files from platforms that claim one codec but carry another; zero-byte uploads after a failed download; short conversion timeouts on slow hardware.","solutions":["Check the stderr in the wrapped error for ffmpeg's exact failure (invalid data, unknown encoder, etc.).","Install an ffmpeg build with AMR support (`ffmpeg -encoders | grep amr_nb`).","Correct the srcFormat on the caller side so it matches the real input codec.","If the error stems from context cancellation, increase the timeout; reject empty payloads before calling."],"exampleFix":"// before\nif err == nil && len(data) == 0 { /* conversion attempted with empty data */ }\namr, err := core.ConvertAudioToAMR(ctx, data, format)\n// after\nif len(data) == 0 {\n    return fmt.Errorf(\"refusing to convert empty audio\")\n}\namr, err := core.ConvertAudioToAMR(ctx, data, format)","handlingStrategy":"try-catch","validationCode":"if len(audio) == 0 || !bytes.HasPrefix(audio, []byte(\"#!AMR\")) && format == \"amr\" {\n    return fmt.Errorf(\"audio payload is not valid AMR\")\n}\n","typeGuard":null,"tryCatchPattern":"amr, err := core.ConvertAudioToAMR(ctx, audio, srcFormat)\nif err != nil {\n    var exitErr *exec.ExitError\n    if errors.As(err, &exitErr) {\n        log.Error(\"AMR conversion failed\", \"stderr\", extractStderr(err))\n    }\n    return fmt.Errorf(\"convert to AMR: %w\", err)\n}","preventionTips":["Confirm the ffmpeg build supports amr_nb (`ffmpeg -encoders | grep amr_nb`).","Check the format declaration against the file's magic bytes before conversion.","Reject empty/truncated downloads at the fetch layer.","Use a context timeout scaled to audio length so conversions are not killed early."],"tags":["ffmpeg","audio","subprocess","amr","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-14T00:17:10.932Z"}