{"record":{"id":"d3a6d1c4ec3fccae","repo":"tonhowtf/omniget","slug":"failed-to-run-ffmpeg","errorCode":null,"errorMessage":"Failed to run ffmpeg: {}","messagePattern":"Failed to run ffmpeg: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/ffmpeg.rs","lineNumber":54,"sourceCode":"        std::fs::create_dir_all(parent)?;\n    }\n\n    let status = crate::core::process::command(\"ffmpeg\")\n        .args([\n            \"-y\",\n            \"-i\",\n            &video.to_string_lossy(),\n            \"-i\",\n            &audio.to_string_lossy(),\n            \"-c\",\n            \"copy\",\n            &output.to_string_lossy(),\n        ])\n        .stdout(std::process::Stdio::null())\n        .stderr(std::process::Stdio::null())\n        .status()\n        .await\n        .map_err(|e| anyhow!(\"Failed to run ffmpeg: {}\", e))?;\n\n    if !status.success() {\n        return Err(anyhow!(\"ffmpeg returned code {}\", status));\n    }\n\n    Ok(())\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct ConversionOptions {\n    pub input_path: String,\n    pub output_path: String,\n    pub video_codec: Option<String>,\n    pub audio_codec: Option<String>,\n    pub resolution: Option<String>,\n    pub video_bitrate: Option<String>,\n    pub audio_bitrate: Option<String>,\n    pub sample_rate: Option<u32>,","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/ffmpeg.rs#L36-L72","documentation":"mux_video_audio spawns `ffmpeg -y -i <video> -i <audio> -c copy <output>` via tokio::process. If spawning/waiting on the ffmpeg process itself fails at the OS level (io::Error from .status()), this error wraps that io error. Note stderr/stdout are piped to null, so ffmpeg's own diagnostics are lost; a non-zero exit code instead produces the separate 'ffmpeg returned code' error.","triggerScenarios":"Calling mux_video_audio when the OS cannot exec or await ffmpeg: binary not on PATH, permission denied on the binary, executable missing/corrupted, or EAGAIN/resource limits on process spawn.","commonSituations":"ffmpeg not installed or not bundled with the Tauri app; PATH differs in the packaged app vs dev environment; sidecar not extracted; antivirus blocks spawning the binary; disk-full or fd-limit conditions.","solutions":["Install ffmpeg or ensure it's on PATH (verify with `which ffmpeg` / `ffmpeg -version`).","In packaged Tauri builds, ship ffmpeg as a sidecar and resolve its absolute path instead of relying on PATH.","Check execute permissions on the binary (chmod +x) and that antivirus isn't quarantining it.","Check is_ffmpeg_available() (which uses find_tool) before calling mux_video_audio to fail fast with a clearer message."],"exampleFix":"// before\nlet status = crate::core::process::command(\"ffmpeg\")\n    .args([\"-y\", \"-i\", &video.to_string_lossy(), \"-i\", &audio.to_string_lossy(), \"-c\", \"copy\", &output.to_string_lossy()])\n    .status()\n    .await\n    .map_err(|e| anyhow!(\"Failed to run ffmpeg: {}\", e))?;\n// after — resolve an explicit binary path and capture stderr for diagnostics\nlet ffmpeg = crate::core::dependencies::find_tool(\"ffmpeg\").await\n    .ok_or_else(|| anyhow!(\"ffmpeg not found; install it or bundle it as a sidecar\"))?;\nlet out = crate::core::process::command(ffmpeg)\n    .args([\"-y\", \"-i\", &video.to_string_lossy(), \"-i\", &audio.to_string_lossy(), \"-c\", \"copy\", &output.to_string_lossy()])\n    .output()\n    .await\n    .map_err(|e| anyhow!(\"Failed to run ffmpeg: {}\", e))?;\nif !out.status.success() {\n    return Err(anyhow!(\"ffmpeg failed: {}\", String::from_utf8_lossy(&out.stderr)));\n}","handlingStrategy":"validation","validationCode":"// Check the tool exists before attempting the mux\nif !crate::core::ffmpeg::is_ffmpeg_available().await {\n    bail!(\"ffmpeg is not installed or not on PATH\");\n}\nfor p in [video, audio] {\n    if !tokio::fs::metadata(p).await.map(|m| m.len() > 0).unwrap_or(false) {\n        bail!(\"input missing or empty: {}\", p.display());\n    }\n}","typeGuard":null,"tryCatchPattern":"// stderr is nulled by the library, so fall back to re-running with capture to obtain the real reason\nmatch mux_video_audio(&video, &audio, &out).await {\n    Err(e) if e.to_string().contains(\"Failed to run ffmpeg\") => {\n        Err(anyhow!(\"ffmpeg could not be started — is it installed? ({e})\"))\n    }\n    other => other,\n}","preventionTips":["Always call is_ffmpeg_available() (or find_tool) before invoking mux_video_audio.","In packaged Tauri apps, bundle ffmpeg as a sidecar and resolve it by absolute path — never rely on the user's PATH.","Keep inputs validated (exists, non-empty, probed via ffprobe) before muxing.","Watch for AV/antivirus policies blocking unsigned helper binaries in production installs."],"tags":["ffmpeg","process-spawn","missing-dependency","rust"],"backgroundTag":"missing-dependency","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}