tonhowtf/omniget · error

No URL available

Error message

No URL available

What it means

download() pulls the first entry from info.available_qualities and falls back to an empty string when the list is empty; if the resulting URL is empty it refuses to proceed. This guard exists because the media-info parse succeeded but contained no downloadable stream URL, so any further download step would fail later with a less clear message.

Solutions

  1. Verify the video is publicly accessible in your region/account and that login cookies (account slug) are configured if the content requires them.
  2. Check how available_qualities is populated upstream (the media-info/parse step) and log the parsed MediaInfo to confirm extraction succeeded.
  3. Return a user-facing, actionable error earlier (at info-extraction time) instead of an empty string default.

Example fix

// before
let url = info.available_qualities.first().map(|q| q.url.as_str()).unwrap_or("");
// after
let url = info.available_qualities.first().map(|q| q.url.as_str())
    .filter(|u| !u.is_empty())
    .ok_or_else(|| anyhow!("No playable stream URL was extracted; the video may be region-locked, deleted, or require login"))?;
Defensive patterns

Strategy: validation

Validate before calling

if info.available_qualities.iter().any(|q| !q.url.is_empty()) { download(info, opts, progress).await?; } else { eprintln!("no playable streams extracted; check login/region"); }

Type guard

fn has_downloadable_url(info: &MediaInfo) -> bool { info.available_qualities.first().map_or(false, |q| !q.url.is_empty()) }

Prevention

When it happens

Trigger: Calling download() (bilibili legacy path) with a MediaInfo whose available_qualities is empty, or whose first quality entry has url == "".

Common situations: The bilibili page/video resolved to no playable streams (region-locked, deleted/audit-pending video, membership-only content fetched without login cookies), or the upstream info extractor changed its response shape and quality extraction silently produced nothing.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/platforms/bilibili/legacy.rs:218

    progress: mpsc::Sender<ProgressUpdate>,
) -> anyhow::Result<DownloadResult> {
    let _ = progress.send(ProgressUpdate::percent(0.0)).await;

    let ytdlp_path = match &opts.ytdlp_path {
        Some(p) => p.clone(),
        None => ytdlp::find_ytdlp_cached()
            .await
            .ok_or_else(|| anyhow!("yt-dlp not found"))?,
    };

    let url = info
        .available_qualities
        .first()
        .map(|q| q.url.as_str())
        .unwrap_or("");

    if url.is_empty() {
        return Err(anyhow!("No URL available"));
    }

    if info.media_type == MediaType::Playlist {
        return download_playlist(info, opts, progress, &ytdlp_path).await;
    }

    let quality_height = opts
        .quality
        .as_ref()
        .and_then(|q| q.trim_end_matches('p').parse::<u32>().ok());

    let extra = vec!["--no-playlist".to_string()];

    ytdlp::download_video(
        &ytdlp_path,
        url,
        &opts.output_dir,
        quality_height,

View on GitHub (pinned to 8600b91f42)