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
- Update yt-dlp to the latest release — YouTube playlist extraction breaks frequently with old versions.
- Open the playlist URL in a browser to confirm it exists, is public, and still contains videos.
- Pass authentication cookies to yt-dlp if the playlist is private or age/region restricted.
- Test manually with `yt-dlp --flat-playlist -J <url>` to see whether yt-dlp itself returns entries or an error.
- 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
- Confirm the playlist exists, is public, and contains videos in a browser before processing.
- Pass authentication cookies to yt-dlp for private or restricted playlists.
- Update yt-dlp regularly — YouTube playlist extraction changes frequently.
- Strip or ignore the `list=` parameter when the URL also targets a single video (v=...).
- Treat YouTube mixes (RD-prefixed list ids) as non-deterministic and avoid batch-fetching them.
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
- Playlist empty or unavailable
- não achei nenhuma faixa em {}
- Download cancelled
- o yt-dlp não baixou nada{}{}
- yt-dlp falhou: {}
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)