tonhowtf/omniget · error

Failed to run ffmpeg: {}

Error message

Failed to run ffmpeg: {}

What it means

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.

Solutions

  1. Install ffmpeg or ensure it's on PATH (verify with `which ffmpeg` / `ffmpeg -version`).
  2. In packaged Tauri builds, ship ffmpeg as a sidecar and resolve its absolute path instead of relying on PATH.
  3. Check execute permissions on the binary (chmod +x) and that antivirus isn't quarantining it.
  4. Check is_ffmpeg_available() (which uses find_tool) before calling mux_video_audio to fail fast with a clearer message.

Example fix

// before
let status = crate::core::process::command("ffmpeg")
    .args(["-y", "-i", &video.to_string_lossy(), "-i", &audio.to_string_lossy(), "-c", "copy", &output.to_string_lossy()])
    .status()
    .await
    .map_err(|e| anyhow!("Failed to run ffmpeg: {}", e))?;
// after — resolve an explicit binary path and capture stderr for diagnostics
let ffmpeg = crate::core::dependencies::find_tool("ffmpeg").await
    .ok_or_else(|| anyhow!("ffmpeg not found; install it or bundle it as a sidecar"))?;
let out = crate::core::process::command(ffmpeg)
    .args(["-y", "-i", &video.to_string_lossy(), "-i", &audio.to_string_lossy(), "-c", "copy", &output.to_string_lossy()])
    .output()
    .await
    .map_err(|e| anyhow!("Failed to run ffmpeg: {}", e))?;
if !out.status.success() {
    return Err(anyhow!("ffmpeg failed: {}", String::from_utf8_lossy(&out.stderr)));
}
Defensive patterns

Strategy: validation

Validate before calling

// Check the tool exists before attempting the mux
if !crate::core::ffmpeg::is_ffmpeg_available().await {
    bail!("ffmpeg is not installed or not on PATH");
}
for p in [video, audio] {
    if !tokio::fs::metadata(p).await.map(|m| m.len() > 0).unwrap_or(false) {
        bail!("input missing or empty: {}", p.display());
    }
}

Try / catch

// stderr is nulled by the library, so fall back to re-running with capture to obtain the real reason
match mux_video_audio(&video, &audio, &out).await {
    Err(e) if e.to_string().contains("Failed to run ffmpeg") => {
        Err(anyhow!("ffmpeg could not be started — is it installed? ({e})"))
    }
    other => other,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/d3a6d1c4ec3fccae. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/ffmpeg.rs:54

        std::fs::create_dir_all(parent)?;
    }

    let status = crate::core::process::command("ffmpeg")
        .args([
            "-y",
            "-i",
            &video.to_string_lossy(),
            "-i",
            &audio.to_string_lossy(),
            "-c",
            "copy",
            &output.to_string_lossy(),
        ])
        .stdout(std::process::Stdio::null())
        .stderr(std::process::Stdio::null())
        .status()
        .await
        .map_err(|e| anyhow!("Failed to run ffmpeg: {}", e))?;

    if !status.success() {
        return Err(anyhow!("ffmpeg returned code {}", status));
    }

    Ok(())
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversionOptions {
    pub input_path: String,
    pub output_path: String,
    pub video_codec: Option<String>,
    pub audio_codec: Option<String>,
    pub resolution: Option<String>,
    pub video_bitrate: Option<String>,
    pub audio_bitrate: Option<String>,
    pub sample_rate: Option<u32>,

View on GitHub (pinned to 8600b91f42)