{"record":{"id":"e8d597b54536b2a9","repo":"tonhowtf/omniget","slug":"failed-to-run-ffprobe","errorCode":null,"errorMessage":"Failed to run ffprobe: {}","messagePattern":"Failed to run ffprobe: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/ffmpeg.rs","lineNumber":130,"sourceCode":"    pub error: Option<String>,\n}\n\npub async fn probe(path: &Path) -> anyhow::Result<MediaProbeInfo> {\n    let output = crate::core::process::command(\"ffprobe\")\n        .args([\n            \"-v\",\n            \"quiet\",\n            \"-print_format\",\n            \"json\",\n            \"-show_format\",\n            \"-show_streams\",\n            &path.to_string_lossy(),\n        ])\n        .stdout(std::process::Stdio::piped())\n        .stderr(std::process::Stdio::piped())\n        .output()\n        .await\n        .map_err(|e| anyhow!(\"Failed to run ffprobe: {}\", e))?;\n\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        return Err(anyhow!(\"ffprobe failed: {}\", stderr));\n    }\n\n    let json: serde_json::Value = serde_json::from_slice(&output.stdout)\n        .map_err(|e| anyhow!(\"Failed to parse ffprobe JSON: {}\", e))?;\n\n    let format = json\n        .get(\"format\")\n        .ok_or_else(|| anyhow!(\"Missing 'format' field\"))?;\n\n    let duration_seconds = format\n        .get(\"duration\")\n        .and_then(|v| v.as_str())\n        .and_then(|s| s.parse::<f64>().ok())\n        .unwrap_or(0.0);","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/ffmpeg.rs#L112-L148","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Install ffprobe (ships with ffmpeg; on Debian `apt install ffmpeg`) and confirm with `ffprobe -version`.","Resolve the binary explicitly via crate::core::dependencies::find_tool(\"ffprobe\") rather than bare \"ffprobe\" on PATH.","In bundled apps, ship ffprobe as a sidecar and point the command at its absolute path.","Check execute permissions and that security software is not blocking process spawn."],"exampleFix":"// before\nlet output = crate::core::process::command(\"ffprobe\")\n    .args([\"-v\", \"quiet\", \"-print_format\", \"json\", \"-show_format\", \"-show_streams\", &path.to_string_lossy()])\n    .output()\n    .await\n    .map_err(|e| anyhow!(\"Failed to run ffprobe: {}\", e))?;\n// after — resolve the tool first for a clear failure mode\nlet ffprobe = crate::core::dependencies::find_tool(\"ffprobe\").await\n    .ok_or_else(|| anyhow!(\"ffprobe not found; install ffmpeg/ffprobe or bundle the sidecar\"))?;\nlet output = crate::core::process::command(ffprobe)\n    .args([\"-v\", \"quiet\", \"-print_format\", \"json\", \"-show_format\", \"-show_streams\", &path.to_string_lossy()])\n    .output()\n    .await\n    .map_err(|e| anyhow!(\"Failed to run ffprobe: {}\", e))?;","handlingStrategy":"validation","validationCode":"// Resolve the tool and the target file before probing\nlet ffprobe = crate::core::dependencies::find_tool(\"ffprobe\").await\n    .ok_or_else(|| anyhow!(\"ffprobe not installed — install ffmpeg or bundle the sidecar\"))?;\nlet md = tokio::fs::metadata(path).await\n    .map_err(|_| anyhow!(\"cannot probe missing file: {}\", path.display()))?;\nif md.len() == 0 { bail!(\"cannot probe empty file: {}\", path.display()); }","typeGuard":null,"tryCatchPattern":"// Distinguish 'tool missing' from other probe failures for actionable messaging\nmatch probe(path).await {\n    Err(e) if e.to_string().contains(\"Failed to run ffprobe\") => {\n        Err(anyhow!(\"ffprobe is not installed or not executable — install ffmpeg first ({e})\"))\n    }\n    other => other,\n}","preventionTips":["Verify ffprobe availability (find_tool(\"ffprobe\") or `ffprobe -version`) at app startup, not at first probe.","Bundle ffprobe as a sidecar in desktop app distributions; GUI-launched processes often have a stripped PATH.","Check both ffmpeg and ffprobe — installing one does not guarantee the other on minimal systems.","Ensure the binary retains execute permissions after extraction/installation."],"tags":["ffprobe","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"}