tonhowtf/omniget · error

yt-dlp

Error message

yt-dlp: {}

What it means

Fallback error for classified yt-dlp failures: when none of the specific stderr patterns matched, the wrapper takes the last error line from yt-dlp's stderr (truncated to 300 chars) and wraps it as anyhow!("yt-dlp: {}"). It represents any unmatched yt-dlp failure.

Solutions

  1. Read the embedded yt-dlp message after the 'yt-dlp:' prefix — it is the actual root cause
  2. Update yt-dlp to the latest release; most extractor errors are fixed upstream
  3. Re-run manually with `yt-dlp -v <url>` for verbose diagnostics
  4. Check rate-limit stats (get_rate_limit_stats) if the message mentions HTTP 429

Example fix

// before
// unmatched stderr -> error swallowed or generic panic
// after
let last_error_line = stderr.lines().rev().find(|l| !l.trim().is_empty());
anyhow!("yt-dlp: {}", msg)
Defensive patterns

Strategy: try-catch

Validate before calling

// keep yt-dlp current; stale extractors cause most unmatched errors
let version = tokio::process::Command::new(&ytdlp).arg("--version").output().await?;
if is_outdated(&version) { prompt_update(); }

Try / catch

match result {
    Err(e) if e.to_string().starts_with("yt-dlp: ") => {
        log::error!("unclassified yt-dlp failure: {e}");
        show_verbose_log_hint(&e);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Any yt-dlp exit failure whose stderr does not match earlier patterns: extractor exceptions, HTTP 403/429 on fragments, postprocessing errors, disk-space errors, or yt-dlp crashes.

Common situations: New site-side changes producing novel errors, yt-dlp version too old for a site, transient CDN errors, or very long/verbose stderr hiding the root cause.

Related errors


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

Appendix: source

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

        .unwrap_or("")
        .trim();

    let msg = if !last_error_line.is_empty() {
        last_error_line
            .strip_prefix("ERROR: ")
            .or_else(|| last_error_line.strip_prefix("ERROR:"))
            .or_else(|| last_error_line.strip_prefix("error: "))
            .unwrap_or(last_error_line)
    } else {
        let trimmed = stderr.trim();
        if trimmed.len() > 300 {
            &trimmed[..300]
        } else {
            trimmed
        }
    };

    anyhow!("yt-dlp: {}", msg)
}

pub fn get_rate_limit_stats() -> serde_json::Value {
    serde_json::json!({
        "rate_limit_429_count": RATE_LIMIT_429_COUNT.load(Ordering::Relaxed)
    })
}

/// Corpo de uma linha do nosso `--progress-template`.
///
/// O `download:` no início do template é consumido pelo yt-dlp como o *tipo*
/// da template (`[TYPES:]TEMPLATE`), então a linha impressa começa direto
/// pelo percentual: `  0.5%|eta:NA|spd:…`. Reconhecemos a linha pelos campos
/// que só o nosso template tem (`|eta:` e `|spd:`), com o prefixo opcional
/// para o caso de o yt-dlp mudar de ideia.
fn template_body(line: &str) -> Option<&str> {
    let t = line.trim();
    if let Some(rest) = t.strip_prefix("download:") {

View on GitHub (pinned to 8600b91f42)