tonhowtf/omniget · error

Failed to run ffprobe

Error message

Failed to run ffprobe: {}

What it means

probe spawns `ffprobe -v quiet -print_format json -show_format -show_streams <path>` and this error wraps the io::Error from spawning or awaiting the ffprobe process. It means ffprobe could not be executed at all — distinct from 'ffprobe failed' (non-zero exit) or the JSON parse error. Callers get_duration_us and convert both depend on probe succeeding.

Solutions

  1. Install ffprobe (ships with ffmpeg; on Debian `apt install ffmpeg`) and confirm with `ffprobe -version`.
  2. Resolve the binary explicitly via crate::core::dependencies::find_tool("ffprobe") rather than bare "ffprobe" on PATH.
  3. In bundled apps, ship ffprobe as a sidecar and point the command at its absolute path.
  4. Check execute permissions and that security software is not blocking process spawn.

Example fix

// before
let output = crate::core::process::command("ffprobe")
    .args(["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", &path.to_string_lossy()])
    .output()
    .await
    .map_err(|e| anyhow!("Failed to run ffprobe: {}", e))?;
// after — resolve the tool first for a clear failure mode
let ffprobe = crate::core::dependencies::find_tool("ffprobe").await
    .ok_or_else(|| anyhow!("ffprobe not found; install ffmpeg/ffprobe or bundle the sidecar"))?;
let output = crate::core::process::command(ffprobe)
    .args(["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", &path.to_string_lossy()])
    .output()
    .await
    .map_err(|e| anyhow!("Failed to run ffprobe: {}", e))?;
Defensive patterns

Strategy: validation

Validate before calling

// Resolve the tool and the target file before probing
let ffprobe = crate::core::dependencies::find_tool("ffprobe").await
    .ok_or_else(|| anyhow!("ffprobe not installed — install ffmpeg or bundle the sidecar"))?;
let md = tokio::fs::metadata(path).await
    .map_err(|_| anyhow!("cannot probe missing file: {}", path.display()))?;
if md.len() == 0 { bail!("cannot probe empty file: {}", path.display()); }

Try / catch

// Distinguish 'tool missing' from other probe failures for actionable messaging
match probe(path).await {
    Err(e) if e.to_string().contains("Failed to run ffprobe") => {
        Err(anyhow!("ffprobe is not installed or not executable — install ffmpeg first ({e})"))
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling probe/get_duration_us/convert when the OS cannot start ffprobe: binary absent from PATH, no execute permission, spawn resource limits, or process wait I/O failure.

Common situations: ffprobe not installed (installed ffmpeg but not the probe utility, or vice versa); packaged Tauri app missing the sidecar; PATH stripped in GUI-launched app context; corrupted tool installation.

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/e8d597b54536b2a9. Report an issue: GitHub.

Appendix: source

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

    pub error: Option<String>,
}

pub async fn probe(path: &Path) -> anyhow::Result<MediaProbeInfo> {
    let output = crate::core::process::command("ffprobe")
        .args([
            "-v",
            "quiet",
            "-print_format",
            "json",
            "-show_format",
            "-show_streams",
            &path.to_string_lossy(),
        ])
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::piped())
        .output()
        .await
        .map_err(|e| anyhow!("Failed to run ffprobe: {}", e))?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        return Err(anyhow!("ffprobe failed: {}", stderr));
    }

    let json: serde_json::Value = serde_json::from_slice(&output.stdout)
        .map_err(|e| anyhow!("Failed to parse ffprobe JSON: {}", e))?;

    let format = json
        .get("format")
        .ok_or_else(|| anyhow!("Missing 'format' field"))?;

    let duration_seconds = format
        .get("duration")
        .and_then(|v| v.as_str())
        .and_then(|s| s.parse::<f64>().ok())
        .unwrap_or(0.0);

View on GitHub (pinned to 8600b91f42)