tonhowtf/omniget · error
No URL available
Error message
No URL available
What it means
After get_media_info succeeds, download picks the first entry of info.available_qualities as the canonical media URL. If that list is empty or the first entry has an empty url string, it fails with 'No URL available' because there is nothing to download.
Solutions
- Re-run get_media_info and check available_qualities is non-empty before calling download.
- Log/inspect the raw yt-dlp JSON (ytdlp::get_video_info result) to see whether the source actually exposes a media URL; if not, the post is likely private, deleted, or geo-blocked.
- Update yt-dlp to the latest version, since extractor fixes often restore missing URL extraction.
- Guard the caller: validate !info.available_qualities.is_empty() and first.url is a non-empty http(s) URL before download.
Example fix
// before
platform.download(opts).await?;
// after
anyhow::ensure!(!info.available_qualities.is_empty(), "no downloadable URL for {url}");
anyhow::ensure!(info.available_qualities[0].url.starts_with("http"), "quality entry has no URL");
platform.download(opts).await?; Defensive patterns
Strategy: validation
Validate before calling
fn has_downloadable_url(info: &MediaInfo) -> bool {
info.available_qualities
.first()
.map(|q| q.url.starts_with("http"))
.unwrap_or(false)
}
// usage: anyhow::ensure!(has_downloadable_url(&info), "media info has no URL"); Type guard
fn first_quality(info: &MediaInfo) -> Option<&Quality> {
info.available_qualities
.first()
.filter(|q| !q.url.is_empty() && q.url.starts_with("http"))
} Try / catch
match platform.download(opts).await {
Err(e) if e.to_string().contains("No URL available") => {
let info = platform.get_media_info(url).await?; // re-extract
if info.available_qualities.is_empty() {
Err(anyhow!("post has no downloadable media (removed/private/geo-blocked?)"))
} else {
platform.download(opts).await
}
}
other => other,
} Prevention
- Always call get_media_info immediately before download and inspect available_qualities.
- Never hand-construct MediaInfo with placeholder URLs.
- Keep yt-dlp updated so URL extraction keeps working against Douyin page changes.
When it happens
Trigger: Calling download(opts) with a MediaInfo whose available_qualities is empty, or whose first quality entry has url == "".
Common situations: Douyin pages where extraction returned metadata but no direct media URL (region-locked or removed posts); a partially populated MediaInfo constructed by the caller instead of returned by get_media_info; upstream HTML/API layout changes that break URL extraction in the parser.
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
- Track sem metadata pra resolver no YouTube
- nenhuma publicação válida na lista
- No quality available
- No audio URL available
- No video quality available
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/6ef694e62d882532.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/platforms/douyin.rs:264
opts: &DownloadOptions,
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 canonical = info
.available_qualities
.first()
.map(|q| q.url.as_str())
.unwrap_or("");
if canonical.is_empty() {
return Err(anyhow!("No URL available"));
}
let canonical = Self::resolve_url(canonical).await;
let quality_height = opts
.quality
.as_ref()
.and_then(|q| q.trim_end_matches('p').parse::<u32>().ok());
let extra = Self::extra_flags();
ytdlp::download_video(
&ytdlp_path,
&canonical,
&opts.output_dir,
quality_height,
progress,
opts.download_mode.as_deref(),
opts.format_id.as_deref(),View on GitHub (pinned to 8600b91f42)