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

  1. Read the stderr in the error message — it names the exact ffmpeg failure (codec, map, I/O).
  2. Validate the thumbnail image format/codec before embedding; convert to PNG/JPEG if needed.
  3. Check free disk space in the target directory.
  4. 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

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)