{"record":{"id":"f610cb5a22a6fc4e","repo":"tonhowtf/omniget","slug":"no-video-url-mod","errorCode":null,"errorMessage":"No video URL","messagePattern":"No video URL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/platforms/reddit/mod.rs","lineNumber":544,"sourceCode":"                    file_size_bytes: None,\n                })\n            }\n        }\n    }\n\n    async fn native_download(\n        &self,\n        info: &MediaInfo,\n        opts: &DownloadOptions,\n        progress: mpsc::Sender<ProgressUpdate>,\n    ) -> anyhow::Result<DownloadResult> {\n        match info.media_type {\n            MediaType::Video => {\n                let video_quality = info\n                    .available_qualities\n                    .iter()\n                    .find(|q| q.label == \"video\")\n                    .ok_or_else(|| anyhow!(\"No video URL\"))?;\n\n                let audio_quality = info.available_qualities.iter().find(|q| q.label == \"audio\");\n\n                let has_audio = audio_quality.is_some();\n                let ffmpeg_available = ffmpeg::is_ffmpeg_available().await;\n\n                if has_audio && !ffmpeg_available {\n                    tracing::warn!(\"[reddit] Video has separate audio but FFmpeg is not installed — downloading video without audio\");\n                }\n\n                if has_audio {\n                    let video_tmp = opts.output_dir.join(format!(\n                        \"{}_video_tmp.mp4\",\n                        sanitize_filename::sanitize(&info.title)\n                    ));\n                    let audio_tmp = opts.output_dir.join(format!(\n                        \"{}_audio_tmp.mp4\",\n                        sanitize_filename::sanitize(&info.title)","sourceCodeStart":526,"sourceCodeEnd":562,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/src/platforms/reddit/mod.rs#L526-L562","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect parse_media to ensure every Video classification also pushes a quality entry with label \"video\".","Log available_qualities when the lookup fails to see what labels were actually produced.","Re-fetch media info fresh instead of caching MediaInfo across requests.","Add a consistency check in parse_media: MediaType::Video must have >=1 'video' quality.","Fall back to the post's direct video URL (media/ or DASH_96.mp4 style) when the labeled entry is absent."],"exampleFix":"// before\nlet video_quality = info.available_qualities.iter()\n    .find(|q| q.label == \"video\")\n    .ok_or_else(|| anyhow!(\"No video URL\"))?;\n// after\nlet video_quality = info.available_qualities.iter().find(|q| q.label == \"video\")\n    .or_else(|| info.available_qualities.iter().find(|q| q.url.contains(\"DASH\") || q.url.ends_with(\".mp4\")))\n    .ok_or_else(|| anyhow!(\"No video URL in qualities: {:?}\",\n        info.available_qualities.iter().map(|q| &q.label).collect::<Vec<_>>()))?;","handlingStrategy":"validation","validationCode":"// sanity-check media info consistency before download\nif info.media_type == MediaType::Video\n    && !info.available_qualities.iter().any(|q| q.label == \"video\") {\n    return Err(\"media info missing video URL; re-fetch media info\");\n}","typeGuard":"fn has_video_entry(info: &MediaInfo) -> bool {\n    info.available_qualities.iter().any(|q| q.label == \"video\" && !q.url.is_empty())\n}","tryCatchPattern":"match download(url, out).await {\n    Err(e) if e.to_string().contains(\"No video URL\") => {\n        let fresh = get_media_info(url).await?; // re-fetch, don't use stale info\n        download_fresh(fresh, out).await\n    }\n    other => other,\n}","preventionTips":["Ensure parse_media always pairs MediaType::Video with a 'video' quality entry","Don't cache MediaInfo across requests — CDN URLs and labels can change","Log available_qualities labels when the lookup fails","Add an invariant check in parse_media so bad state fails at creation time"],"tags":["reddit","download","media-parsing","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}