tonhowtf/omniget · error
Failed to parse ffprobe JSON
Error message
Failed to parse ffprobe JSON: {} What it means
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.
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.
Example fix
// before
let json: serde_json::Value = serde_json::from_slice(&output.stdout)
.map_err(|e| anyhow!("Failed to parse ffprobe JSON: {}", e))?;
// after
let stdout = String::from_utf8_lossy(&output.stdout);
if stdout.trim().is_empty() {
anyhow::bail!("ffprobe returned empty output; check the file exists and ffprobe version");
}
let json: serde_json::Value = serde_json::from_str(stdout.trim())
.map_err(|e| anyhow!("Failed to parse ffprobe JSON: {} (stdout: {:.200})", e, stdout))? Defensive patterns
Strategy: try-catch
Validate before calling
let out = std::process::Command::new("ffprobe")
.args(["-v", "quiet", "-print_format", "json", "-show_format", path])
.output()
.map_err(|e| format!("ffprobe not runnable: {e}"))?;
if !out.status.success() || out.stdout.trim().is_empty() {
return Err("ffprobe output empty or failed".into());
} Type guard
fn looks_like_ffprobe_json(stdout: &[u8]) -> bool {
serde_json::from_slice::<serde_json::Value>(stdout)
.map(|v| v.get("format").is_some())
.unwrap_or(false)
} Try / catch
match probe(path).await {
Err(e) if e.to_string().contains("Failed to parse ffprobe JSON") => {
log::warn!("ffprobe output unusable, skipping duration: {e}");
Duration::ZERO // degraded mode
}
other => other,
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/c79c27a05930ed8e.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/ffmpeg.rs:138
"-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);
let format_name = format
.get("format_name")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let format_long_name = formatView on GitHub (pinned to 8600b91f42)