tonhowtf/omniget · error

No video URL

Error message

No video URL

What it means

For video posts, native_download searches available_qualities for an entry labeled 'video'; if media info produced no such entry it cannot download and throws 'No video URL'. This is an internal invariant: a video-type MediaInfo should always carry a video quality entry.

Solutions

  1. Inspect parse_media to ensure every Video classification also pushes a quality entry with label "video".
  2. Log available_qualities when the lookup fails to see what labels were actually produced.
  3. Re-fetch media info fresh instead of caching MediaInfo across requests.
  4. Add a consistency check in parse_media: MediaType::Video must have >=1 'video' quality.
  5. Fall back to the post's direct video URL (media/ or DASH_96.mp4 style) when the labeled entry is absent.

Example fix

// before
let video_quality = info.available_qualities.iter()
    .find(|q| q.label == "video")
    .ok_or_else(|| anyhow!("No video URL"))?;
// after
let video_quality = info.available_qualities.iter().find(|q| q.label == "video")
    .or_else(|| info.available_qualities.iter().find(|q| q.url.contains("DASH") || q.url.ends_with(".mp4")))
    .ok_or_else(|| anyhow!("No video URL in qualities: {:?}",
        info.available_qualities.iter().map(|q| &q.label).collect::<Vec<_>>()))?;
Defensive patterns

Strategy: validation

Validate before calling

// sanity-check media info consistency before download
if info.media_type == MediaType::Video
    && !info.available_qualities.iter().any(|q| q.label == "video") {
    return Err("media info missing video URL; re-fetch media info");
}

Type guard

fn has_video_entry(info: &MediaInfo) -> bool {
    info.available_qualities.iter().any(|q| q.label == "video" && !q.url.is_empty())
}

Try / catch

match download(url, out).await {
    Err(e) if e.to_string().contains("No video URL") => {
        let fresh = get_media_info(url).await?; // re-fetch, don't use stale info
        download_fresh(fresh, out).await
    }
    other => other,
}

Prevention

When it happens

Trigger: parse_media classified the post as MediaType::Video but failed to populate an available_qualities entry with label == "video" (e.g. missing fallback_url / HLS URL), or a schema change renamed/removed that field.

Common situations: Reddit posts with video but no DASH fallback_url (rare API responses); posts where video exists only as crosspost/gallery item; a regression in parse_media after a Reddit API change; reusing cached MediaInfo from another post type.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/src/platforms/reddit/mod.rs:544

                    file_size_bytes: None,
                })
            }
        }
    }

    async fn native_download(
        &self,
        info: &MediaInfo,
        opts: &DownloadOptions,
        progress: mpsc::Sender<ProgressUpdate>,
    ) -> anyhow::Result<DownloadResult> {
        match info.media_type {
            MediaType::Video => {
                let video_quality = info
                    .available_qualities
                    .iter()
                    .find(|q| q.label == "video")
                    .ok_or_else(|| anyhow!("No video URL"))?;

                let audio_quality = info.available_qualities.iter().find(|q| q.label == "audio");

                let has_audio = audio_quality.is_some();
                let ffmpeg_available = ffmpeg::is_ffmpeg_available().await;

                if has_audio && !ffmpeg_available {
                    tracing::warn!("[reddit] Video has separate audio but FFmpeg is not installed — downloading video without audio");
                }

                if has_audio {
                    let video_tmp = opts.output_dir.join(format!(
                        "{}_video_tmp.mp4",
                        sanitize_filename::sanitize(&info.title)
                    ));
                    let audio_tmp = opts.output_dir.join(format!(
                        "{}_audio_tmp.mp4",
                        sanitize_filename::sanitize(&info.title)

View on GitHub (pinned to 8600b91f42)