tonhowtf/omniget · error · anyhow::Error
ffmpeg metadata failed
Error message
ffmpeg metadata failed: {} What it means
After embed_metadata() runs ffmpeg, a non-zero exit status causes the captured stderr to be captured and returned as this error, and the temp output file is cleaned up. This is how ffmpeg's own failures (bad args, unreadable thumbnail, unsupported codec) surface to callers.
Solutions
- Read the stderr in the error message — it names the exact ffmpeg failure (codec, map, I/O).
- Validate the thumbnail image format/codec before embedding; convert to PNG/JPEG if needed.
- Check free disk space in the target directory.
- Test the exact ffmpeg command manually in a shell to reproduce and iterate on the arguments.
Example fix
// before
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(anyhow!("ffmpeg metadata failed: {}", stderr));
// after
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(anyhow!(
"ffmpeg metadata failed (exit {:?}): {}",
output.status.code(),
stderr
)); Defensive patterns
Strategy: try-catch
Validate before calling
// validate thumbnail bytes are a decodable image before embedding
let kind = image::guess_format(&thumb_bytes)
.map_err(|_| "thumbnail is not a recognized image format")?;
if !matches!(kind, image::ImageFormat::Jpeg | image::ImageFormat::Png) {
return Err("convert thumbnail to JPEG/PNG before embedding".into());
} Try / catch
match embed_metadata(/* ... */).await {
Err(e) if e.to_string().contains("ffmpeg metadata failed") => {
let stderr = e.to_string();
if stderr.contains("Could not find tag") || stderr.contains("codec") {
log::warn!("unsupported embed target/thumbnail: {stderr}");
// keep original file without embedded metadata
} else {
return Err(e);
}
}
other => other?,
} Prevention
- Always read the stderr inside the error before deciding on a fallback
- Pre-validate metadata key/value strings and thumbnail formats
- Test the equivalent ffmpeg command in a shell when iterating on args
- Check disk space before long embed operations
When it happens
Trigger: Calling embed_metadata with an invalid metadata field value, a thumbnail URL that downloaded into a corrupt/unsupported image, or an output container that rejects one of the stream copy operations.
Common situations: Embedding a WebP thumbnail into MP4 (older ffmpeg lacks support); bad -metadata key/value strings with unescaped characters; disk full causing ffmpeg write errors; wrong -map arguments.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/1729d87c1dafe943.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/ffmpeg.rs:537
args.push(temp_output.to_string_lossy().to_string());
let output = crate::core::process::command("ffmpeg")
.args(&args)
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.output()
.await
.map_err(|e| anyhow!("Failed to run ffmpeg: {}", e))?;
if let Some(ref thumb) = thumbnail_path {
let _ = std::fs::remove_file(thumb);
}
if !output.status.success() {
let _ = std::fs::remove_file(&temp_output);
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(anyhow!("ffmpeg metadata failed: {}", stderr));
}
let mut rename_ok = false;
for attempt in 0..3 {
match std::fs::rename(&temp_output, file) {
Ok(()) => {
rename_ok = true;
break;
}
Err(e) if attempt < 2 => {
tracing::warn!(
"Failed to replace file (attempt {}): {}, retrying...",
attempt + 1,
e
);
tokio::time::sleep(std::time::Duration::from_millis(500 * (attempt as u64 + 1)))
.await;
}View on GitHub (pinned to 8600b91f42)