{"record":{"id":"c79c27a05930ed8e","repo":"tonhowtf/omniget","slug":"failed-to-parse-ffprobe-json","errorCode":null,"errorMessage":"Failed to parse ffprobe JSON: {}","messagePattern":"Failed to parse ffprobe JSON: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/ffmpeg.rs","lineNumber":138,"sourceCode":"            \"-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);\n\n    let format_name = format\n        .get(\"format_name\")\n        .and_then(|v| v.as_str())\n        .unwrap_or(\"\")\n        .to_string();\n\n    let format_long_name = format","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/ffmpeg.rs#L120-L156","documentation":"probe() runs ffprobe and parses its stdout as JSON. When serde_json cannot deserialize the output (e.g. empty, truncated, or non-JSON stdout), the parse error is wrapped into this anyhow error. It signals that ffprobe ran but its output was not the expected JSON stream.","triggerScenarios":"Calling get_duration_us or convert on a file whose ffprobe invocation exits successfully but prints invalid/empty JSON to stdout (e.g. ffprobe binary replaced by a wrapper script, stdout polluted by other output, or a broken ffprobe build).","commonSituations":"A shim/wrapper around ffprobe adds banners to stdout; a corrupted or very old ffprobe build that doesn't support -print_format json; PATH pointing to the wrong binary; output truncated by an unusual locale/encoding wrapper.","solutions":["Run `ffprobe -v quiet -print_format json -show_format <file>` manually on the failing file and inspect raw stdout.","Verify the ffprobe on PATH (`which ffprobe`) is the real binary, not a script that prints extra output.","Log output.stdout bytes on failure to confirm whether it is empty or malformed.","Upgrade/reinstall ffprobe to a version that supports JSON output."],"exampleFix":"// before\nlet json: serde_json::Value = serde_json::from_slice(&output.stdout)\n    .map_err(|e| anyhow!(\"Failed to parse ffprobe JSON: {}\", e))?;\n// after\nlet stdout = String::from_utf8_lossy(&output.stdout);\nif stdout.trim().is_empty() {\n    anyhow::bail!(\"ffprobe returned empty output; check the file exists and ffprobe version\");\n}\nlet json: serde_json::Value = serde_json::from_str(stdout.trim())\n    .map_err(|e| anyhow!(\"Failed to parse ffprobe JSON: {} (stdout: {:.200})\", e, stdout))?","handlingStrategy":"try-catch","validationCode":"let out = std::process::Command::new(\"ffprobe\")\n    .args([\"-v\", \"quiet\", \"-print_format\", \"json\", \"-show_format\", path])\n    .output()\n    .map_err(|e| format!(\"ffprobe not runnable: {e}\"))?;\nif !out.status.success() || out.stdout.trim().is_empty() {\n    return Err(\"ffprobe output empty or failed\".into());\n}","typeGuard":"fn looks_like_ffprobe_json(stdout: &[u8]) -> bool {\n    serde_json::from_slice::<serde_json::Value>(stdout)\n        .map(|v| v.get(\"format\").is_some())\n        .unwrap_or(false)\n}","tryCatchPattern":"match probe(path).await {\n    Err(e) if e.to_string().contains(\"Failed to parse ffprobe JSON\") => {\n        log::warn!(\"ffprobe output unusable, skipping duration: {e}\");\n        Duration::ZERO // degraded mode\n    }\n    other => other,\n}","preventionTips":["Never wrap ffprobe in a script that writes to stdout","Log raw ffprobe stdout when parsing fails to speed diagnosis","Pin a known-good ffprobe version in CI and install docs"],"tags":["ffmpeg","ffprobe","json-parse","external-process"],"backgroundTag":"json-parse-error","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"}