tonhowtf/omniget · error
No video quality available
Error message
No video quality available
What it means
Raised by native_get_media_info after the clip metadata GraphQL query succeeds but the returned videoQualities array is empty, meaning Twitch returned the clip record with no playable quality renditions.
Solutions
- Fall back to the yt-dlp-based extraction path for the clip
- Re-check the clip in a browser to confirm it still exists and is public
- Add logging on the parsed videoQualities count to detect GQL schema drift
Example fix
// before
if clip.video_qualities.is_empty() {
return Err(anyhow!("No video quality available"));
}
// after
if clip.video_qualities.is_empty() {
return self.fallback_ytdlp(url).await;
} Defensive patterns
Strategy: fallback
Validate before calling
// After get_media_info succeeds, before download:
if info.available_qualities.is_empty() {
eprintln!("Twitch clip exposed no qualities; clip may be deleted or restricted");
} Type guard
fn has_playable_qualities(info: &MediaInfo) -> bool {
!info.available_qualities.is_empty() && info.available_qualities.iter().all(|q| !q.url.is_empty())
} Try / catch
match downloader.get_media_info(url).await {
Err(e) if e.to_string().contains("No video quality available") => fallback_ytdlp_info(url).await,
other => other,
} Prevention
- Confirm the clip is public and not subscriber-only before downloading
- Use the yt-dlp fallback whenever native extraction yields no qualities
- Monitor GQL videoQualities shape so filter_map silently dropping entries is caught
When it happens
Trigger: fetch_clip_metadata returns a clip whose videoQualities array is empty — typical for deleted/expired clips, sub-only content, or clips in restricted regions; also when the GQL response fields are filtered out.
Common situations: A clip was deleted or made subscriber-only after the link was shared; geo-restriction strips renditions; Twitch API changes the videoQualities shape so all entries are filtered by filter_map.
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
- Dados do clip incompletos
- Twitch GQL retornou HTTP
- No media URL available
- Track sem soundcloud_id
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/e0d250af16abb0b0.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/platforms/twitch.rs:56
Self::new()
}
}
impl TwitchClipsDownloader {
async fn fallback_ytdlp(&self, url: &str) -> anyhow::Result<MediaInfo> {
let ytdlp_path = crate::core::ytdlp::ensure_ytdlp().await?;
let json = crate::core::ytdlp::get_video_info(&ytdlp_path, url, &[]).await?;
crate::platforms::generic_ytdlp::GenericYtdlpDownloader::parse_video_info(&json)
}
async fn native_get_media_info(&self, url: &str) -> anyhow::Result<MediaInfo> {
let slug =
Self::extract_clip_slug(url).ok_or_else(|| anyhow!("Could not extract clip slug"))?;
let clip = self.fetch_clip_metadata(&slug).await?;
if clip.video_qualities.is_empty() {
return Err(anyhow!("No video quality available"));
}
let broadcaster = clip
.broadcaster_login
.as_deref()
.ok_or_else(|| anyhow!("Dados do clip incompletos"))?;
let token = self.fetch_access_token(&slug).await?;
let clip_title = clip.title.trim().to_string();
let available_qualities: Vec<VideoQuality> = clip
.video_qualities
.iter()
.map(|q| {
let height: u32 = q.quality.parse().unwrap_or(0);
let authenticated_url = Self::build_authenticated_url(&q.source_url, &token);
VideoQuality {View on GitHub (pinned to 8600b91f42)