{"record":{"id":"47ee055767b22236","repo":"tonhowtf/omniget","slug":"failed-to-run-yt-dlp","errorCode":null,"errorMessage":"Failed to run yt-dlp: {}","messagePattern":"Failed to run yt-dlp: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/ytdlp.rs","lineNumber":2319,"sourceCode":"                );\n                log_hook::emit_log(dl_id, &line);\n            }\n        }\n        if let Some(proxy_url) = proxy {\n            args.push(\"--proxy\".to_string());\n            args.push(proxy_url);\n        }\n        args.extend(extra_flags.iter().cloned());\n        args.push(url.to_string());\n\n        let _slot = acquire_ytdlp_slot(\"video info\").await;\n        let child = ytdlp_command(ytdlp)\n            .args(&args)\n            .stdout(Stdio::piped())\n            .stderr(Stdio::piped())\n            .kill_on_drop(true)\n            .spawn()\n            .map_err(|e| anyhow!(\"Failed to run yt-dlp: {}\", e))?;\n        tracing::debug!(\n            \"[perf] get_video_info: yt-dlp process spawned at {:?} (attempt {})\",\n            _timer_start.elapsed(),\n            attempt + 1\n        );\n\n        let result = tokio::time::timeout(\n            std::time::Duration::from_secs(VIDEO_INFO_PROCESS_TIMEOUT_SECS),\n            child.wait_with_output(),\n        )\n        .await\n        .map_err(|_| {\n            tracing::debug!(\"[perf] get_video_info took {:?}\", _timer_start.elapsed());\n            anyhow!(\n                \"Timeout fetching video info ({}s)\",\n                VIDEO_INFO_PROCESS_TIMEOUT_SECS\n            )\n        })?","sourceCodeStart":2301,"sourceCodeEnd":2337,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/ytdlp.rs#L2301-L2337","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the yt-dlp binary path exists and is executable (chmod +x, or reinstall yt-dlp)","Log the io::Error kind to distinguish NotFound vs PermissionDenied and fix accordingly","If relying on PATH, ensure PATH inside the app process includes the yt-dlp location","Retry after fixing; the code already loops attempts but spawn failure is not transient"],"exampleFix":"// before\nlet child = ytdlp_command(ytdlp).args(&args).spawn().map_err(|e| anyhow!(\"Failed to run yt-dlp: {}\", e))?;\n// after\nlet child = ytdlp_command(ytdlp).args(&args).spawn().map_err(|e| {\n    if e.kind() == std::io::ErrorKind::NotFound {\n        anyhow!(\"yt-dlp binary not found at '{}'; install yt-dlp or fix the configured path\", ytdlp)\n    } else {\n        anyhow!(\"Failed to run yt-dlp: {}\", e)\n    }\n})?;","handlingStrategy":"try-catch","validationCode":"let meta = std::fs::metadata(ytdlp);\nif meta.is_err() { return Err(\"yt-dlp binary not found at configured path\".into()); }\n#[cfg(unix)]\n{\n    use std::os::unix::fs::PermissionsExt;\n    if meta.unwrap().permissions().mode() & 0o111 == 0 {\n        return Err(\"yt-dlp binary is not executable\".into());\n    }\n}","typeGuard":"fn yt_dlp_binary_ok(path: &str) -> bool {\n    std::fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)\n}","tryCatchPattern":"match get_video_info(url).await {\n    Err(e) if e.to_string().contains(\"Failed to run yt-dlp\") => {\n        // binary missing/not executable: prompt install or path fix\n    }\n    Err(e) => return Err(e),\n    Ok(info) => info,\n}","preventionTips":["Ship and verify the yt-dlp binary at startup with a version check (yt-dlp --version)","Never let users set a raw binary path without validating existence and exec permission","In packaged apps, ensure the bundled binary keeps the executable bit (e.g. set in build scripts)","Log the io::Error kind, not just the message, for faster diagnosis"],"tags":["rust","ytdlp","process-spawn","tauri"],"backgroundTag":"command-not-found","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"}