tonhowtf/omniget · error

Failed to run yt-dlp

Error message

Failed to run yt-dlp: {}

What it means

This error is raised in get_video_info when the yt-dlp child process cannot be spawned via tokio::process::Command::spawn(). It wraps the underlying io::Error, so it fires before any network or parsing work happens. Typically the yt-dlp binary is missing, not executable, or the configured path is wrong.

Solutions

  1. Verify the yt-dlp binary path exists and is executable (chmod +x, or reinstall yt-dlp)
  2. Log the io::Error kind to distinguish NotFound vs PermissionDenied and fix accordingly
  3. If relying on PATH, ensure PATH inside the app process includes the yt-dlp location
  4. Retry after fixing; the code already loops attempts but spawn failure is not transient

Example fix

// before
let child = ytdlp_command(ytdlp).args(&args).spawn().map_err(|e| anyhow!("Failed to run yt-dlp: {}", e))?;
// after
let child = ytdlp_command(ytdlp).args(&args).spawn().map_err(|e| {
    if e.kind() == std::io::ErrorKind::NotFound {
        anyhow!("yt-dlp binary not found at '{}'; install yt-dlp or fix the configured path", ytdlp)
    } else {
        anyhow!("Failed to run yt-dlp: {}", e)
    }
})?;
Defensive patterns

Strategy: try-catch

Validate before calling

let meta = std::fs::metadata(ytdlp);
if meta.is_err() { return Err("yt-dlp binary not found at configured path".into()); }
#[cfg(unix)]
{
    use std::os::unix::fs::PermissionsExt;
    if meta.unwrap().permissions().mode() & 0o111 == 0 {
        return Err("yt-dlp binary is not executable".into());
    }
}

Type guard

fn yt_dlp_binary_ok(path: &str) -> bool {
    std::fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)
}

Try / catch

match get_video_info(url).await {
    Err(e) if e.to_string().contains("Failed to run yt-dlp") => {
        // binary missing/not executable: prompt install or path fix
    }
    Err(e) => return Err(e),
    Ok(info) => info,
}

Prevention

When it happens

Trigger: Calling get_video_info with a `ytdlp` path that does not exist, is not executable, or resolves to a binary that fails to exec (e.g. permission denied, ENOENT); also OS-level process spawn limits being exhausted after all retry attempts.

Common situations: yt-dlp not installed or not on PATH; bundled binary shipped without the executable bit; users overriding the yt-dlp path with a typo'd setting; running inside a container/sandbox that forbids exec of that path.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/47ee055767b22236. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/ytdlp.rs:2319

                );
                log_hook::emit_log(dl_id, &line);
            }
        }
        if let Some(proxy_url) = proxy {
            args.push("--proxy".to_string());
            args.push(proxy_url);
        }
        args.extend(extra_flags.iter().cloned());
        args.push(url.to_string());

        let _slot = acquire_ytdlp_slot("video info").await;
        let child = ytdlp_command(ytdlp)
            .args(&args)
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .kill_on_drop(true)
            .spawn()
            .map_err(|e| anyhow!("Failed to run yt-dlp: {}", e))?;
        tracing::debug!(
            "[perf] get_video_info: yt-dlp process spawned at {:?} (attempt {})",
            _timer_start.elapsed(),
            attempt + 1
        );

        let result = tokio::time::timeout(
            std::time::Duration::from_secs(VIDEO_INFO_PROCESS_TIMEOUT_SECS),
            child.wait_with_output(),
        )
        .await
        .map_err(|_| {
            tracing::debug!("[perf] get_video_info took {:?}", _timer_start.elapsed());
            anyhow!(
                "Timeout fetching video info ({}s)",
                VIDEO_INFO_PROCESS_TIMEOUT_SECS
            )
        })?

View on GitHub (pinned to 8600b91f42)