tonhowtf/omniget · error

Playlist empty or unavailable

Error message

Playlist empty or unavailable

What it means

In YouTube's `fetch_with_ytdlp` (src-tauri/omniget-core/src/platforms/youtube.rs:87), when the URL is detected as a playlist via `is_playlist_url`, the code fetches entries with `ytdlp::get_playlist_info` and throws 'Playlist empty or unavailable' if the returned entry list is empty. It signals that although the URL looked like a playlist, yt-dlp produced no playlist entries — the playlist is private, deleted, region-blocked, or the fetch silently failed.

Solutions

  1. Update yt-dlp to the latest release — YouTube playlist extraction breaks frequently with old versions.
  2. Open the playlist URL in a browser to confirm it exists, is public, and still contains videos.
  3. Pass authentication cookies to yt-dlp if the playlist is private or age/region restricted.
  4. Test manually with `yt-dlp --flat-playlist -J <url>` to see whether yt-dlp itself returns entries or an error.
  5. Verify is_playlist_url isn't misclassifying a single-video URL with a stray `list=` parameter; strip the param or handle it as a single video.

Example fix

// before: empty entries abort with a generic error
let (playlist_title, entries) = ytdlp::get_playlist_info(ytdlp_path, url, &[]).await?;
if entries.is_empty() {
    return Err(anyhow!("Playlist empty or unavailable"));
}

// after: retry once with fresh cookies and single-video fallback
let (playlist_title, entries) = ytdlp::get_playlist_info(ytdlp_path, url, &[]).await?;
let entries = if entries.is_empty() {
    tracing::warn!("[youtube] playlist empty; retrying with auth cookies");
    let (_t, retried) = ytdlp::get_playlist_info(ytdlp_path, url, &["--cookies-from-browser", "firefox"]).await?;
    if retried.is_empty() && !Self::is_single_video_url(url) {
        return Err(anyhow!("Playlist empty or unavailable"));
    }
    retried
} else { entries };
Defensive patterns

Strategy: validation

Validate before calling

// Validate the playlist is resolvable before calling the library
let probe = tokio::process::Command::new("yt-dlp")
    .args(["--flat-playlist", "--print", "id", "--playlist-items", "1", url])
    .output().await?;
if probe.stdout.is_empty() {
    anyhow::bail!("playlist is empty, private, or deleted — check it in a browser first");
}

Type guard

fn is_playlist_id(url: &str) -> bool {
    url.contains("playlist?list=")
        && url.split("list=").nth(1)
            .map(|id| !id.is_empty() && !id.starts_with("RD")) // RD* are mixes yt-dlp may not enumerate
            .unwrap_or(false)
}

Try / catch

match youtube.get_media_info(playlist_url).await {
    Ok(info) => use_media(info),
    Err(e) if e.to_string().contains("Playlist empty or unavailable") => {
        eprintln!("Playlist is empty/private/deleted; verify URL or pass cookies to yt-dlp");
        // fall back to treating the URL as a single video if a v= param is present
        if let Some(video_url) = extract_single_video_url(playlist_url) {
            youtube.get_media_info(&video_url).await
        } else {
            Err(e)
        }
    }
    Err(e) => report(e),
}

Prevention

When it happens

Trigger: Calling native_get_media_info (via fetch_with_ytdlp) with a playlist URL (e.g., youtube.com/playlist?list=...) where get_playlist_info returns zero entries: deleted playlist, private/unlisted playlist without credentials, yt-dlp parse failure swallowed into an empty list, or a `list=` parameter pointing at an inaccessible mix.

Common situations: Stale playlist URLs whose videos were all removed, private playlists of the requesting user without passing cookies to yt-dlp, region-restricted playlists, YouTube mixes/radio lists yt-dlp can't enumerate, or an outdated yt-dlp after a YouTube API/markup change.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/platforms/youtube.rs:87

                if key == "v" && !value.is_empty() {
                    has_video = true;
                }
            }

            return has_list && !has_video;
        }
        false
    }

    pub async fn fetch_with_ytdlp(
        url: &str,
        ytdlp_path: &std::path::Path,
    ) -> anyhow::Result<MediaInfo> {
        if Self::is_playlist_url(url) {
            let (playlist_title, entries) = ytdlp::get_playlist_info(ytdlp_path, url, &[]).await?;

            if entries.is_empty() {
                return Err(anyhow!("Playlist empty or unavailable"));
            }

            let qualities: Vec<MediaVideoQuality> = entries
                .into_iter()
                .enumerate()
                .map(|(i, entry)| MediaVideoQuality {
                    label: format!("{}. {}", i + 1, entry.title),
                    width: 0,
                    height: 0,
                    url: entry.url,
                    format: "ytdlp_playlist".to_string(),
                })
                .collect();

            return Ok(MediaInfo {
                title: sanitize_filename::sanitize(&playlist_title),
                author: playlist_title,
                platform: "youtube".to_string(),

View on GitHub (pinned to 8600b91f42)