{"record":{"id":"052d2999b8027191","repo":"tonhowtf/omniget","slug":"no-media-url-available-twitch","errorCode":null,"errorMessage":"No media URL available","messagePattern":"No media URL available","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/platforms/twitch.rs","lineNumber":327,"sourceCode":"                    opts.download_mode.as_deref(),\n                    opts.format_id.as_deref(),\n                    opts.filename_template.as_deref(),\n                    opts.referer.as_deref().or(Some(\"https://www.twitch.tv/\")),\n                    opts.cancel_token.clone(),\n                    None,\n                    opts.concurrent_fragments,\n                    false,\n                    &[],\n                    opts.audio_format.as_deref(),\n                )\n                .await;\n            }\n        }\n\n        let first = info\n            .available_qualities\n            .first()\n            .ok_or_else(|| anyhow!(\"No media URL available\"))?;\n\n        let selected = if let Some(ref wanted) = opts.quality {\n            info.available_qualities\n                .iter()\n                .find(|q| q.label == *wanted)\n                .unwrap_or(first)\n        } else {\n            first\n        };\n\n        let filename = format!(\n            \"{}_{}.mp4\",\n            sanitize_filename::sanitize(&info.title),\n            selected.label\n        );\n        let output_path = opts.output_dir.join(&filename);\n\n        let total_bytes = direct_downloader::download_direct(","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/twitch.rs#L309-L345","documentation":"Thrown in download when info.available_qualities is empty after fetching media info, meaning no downloadable media URL was resolved for the Twitch resource. The downloader takes the first (or quality-matched) entry from that list, so an empty list makes selection impossible.","triggerScenarios":"native_get_media_info returned Ok with zero entries in available_qualities — e.g. the token/url extraction found formats but all were filtered out, or extraction silently produced nothing.","commonSituations":"VOD/clip deleted or sub-only so no playable formats exist; all qualities unsupported (e.g. only HLS ads); parsing bug after a Twitch player API change.","solutions":["Check the media actually exists and is playable on Twitch","Inspect media_info extraction logs for filtered-out formats","Handle sub-only/removed content explicitly before calling download","Retry with quality=None to accept the default"],"exampleFix":"// before\nlet first = info.available_qualities.first().ok_or_else(|| anyhow!(\"No media URL available\"))?;\n// after\nif info.available_qualities.is_empty() {\n    anyhow::bail!(\"No media URL available for {} (removed, sub-only, or unsupported)\", opts.url);\n}\nlet first = &info.available_qualities[0];","handlingStrategy":"validation","validationCode":"// check before download\nif info.available_qualities.is_empty() {\n    // skip download or surface a user-facing 'media unavailable' state\n}","typeGuard":null,"tryCatchPattern":"match downloader.download(opts).await {\n    Err(e) if e.to_string() == \"No media URL available\" => {\n        ui.show_unavailable(&opts.url);\n    }\n    Err(e) => return Err(e.into()),\n    Ok(path) => ui.show_done(path),\n}","preventionTips":["Verify the media is playable in a browser before batch downloading","Skip sub-only or members-only content explicitly","Check available_qualities length before invoking download","Keep extraction parsers updated against the live player API"],"tags":["twitch","empty-list","download","rust"],"backgroundTag":"empty-result-set","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"}