{"record":{"id":"e75b319f534a77ff","repo":"tonhowtf/omniget","slug":"download-cancelado","errorCode":null,"errorMessage":"Download cancelado","messagePattern":"Download cancelado","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src-tauri/src/platforms/youtube/mod.rs","lineNumber":400,"sourceCode":"        opts: &DownloadOptions,\n        progress: mpsc::Sender<ProgressUpdate>,\n        ytdlp_path: &std::path::Path,\n        quality_height: Option<u32>,\n    ) -> anyhow::Result<DownloadResult> {\n        let playlist_dir = opts\n            .output_dir\n            .join(sanitize_filename::sanitize(&info.title));\n        tokio::fs::create_dir_all(&playlist_dir).await?;\n\n        let total = info.available_qualities.len();\n        let mut total_bytes = 0u64;\n        let mut last_path = playlist_dir.clone();\n        let mut success_count = 0usize;\n        let mut last_err: Option<anyhow::Error> = None;\n\n        for (i, entry) in info.available_qualities.iter().enumerate() {\n            if opts.cancel_token.is_cancelled() {\n                anyhow::bail!(\"Download cancelado\");\n            }\n\n            let (video_tx, mut video_rx) = mpsc::channel::<ProgressUpdate>(16);\n            let progress_tx = progress.clone();\n            let video_idx = i;\n            let video_total = total;\n            let forwarder = tokio::spawn(async move {\n                let mut max_pct = 0.0_f64;\n                while let Some(pu) = video_rx.recv().await {\n                    max_pct = max_pct.max(pu.percent);\n                    let overall = (video_idx as f64 / video_total as f64) * 100.0\n                        + (max_pct / video_total as f64);\n                    let _ = progress_tx\n                        .send(ProgressUpdate::rich(\n                            overall,\n                            None,\n                            None,\n                            pu.speed_bps,","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/src/platforms/youtube/mod.rs#L382-L418","documentation":"anyhow::bail! raised inside `download_playlist` when `opts.cancel_token.is_cancelled()` becomes true before starting the next video in the playlist loop. This is an intentional cooperative-cancellation error: the playlist download stops partway, carrying the count of already-successful items via success_count.","triggerScenarios":"User clicks cancel in the UI while a YouTube playlist download loop is iterating `info.available_qualities` entries; each iteration checks the cancel token and aborts with this message.","commonSituations":"User realizes playlist is too large and cancels mid-run; app shutdown triggers the cancel token; duplicate cancel requests from the frontend while previous loop is still draining progress channels.","solutions":["Treat this message as an expected user-intent outcome, not a failure — check cancel_token state or match on the message and suppress error UI","Show partial-success info using success_count (N of M videos completed)","Clear/reset the cancel token after cancellation so subsequent downloads are not immediately aborted"],"exampleFix":"// before\nmatch download_playlist(...) { Err(e) => show_error(e) }\n// after\nif let Err(e) = download_playlist(...) {\n    if e.to_string() != \"Download cancelado\" { show_error(e); }\n}","handlingStrategy":"try-catch","validationCode":"// pre-check: if opts.cancel_token.is_cancelled() { return early before starting }","typeGuard":null,"tryCatchPattern":"match download_playlist(...) {\n    Err(e) if e.to_string() == \"Download cancelado\" => log::info!(\"cancelled by user\"),\n    Err(e) => show_error(e),\n    Ok(_) => {}\n}","preventionTips":["Reset cancel tokens after each run","Surface partial progress so users cancel knowingly","Treat cancellation as a control-flow outcome, not an error"],"tags":["rust","anyhow","youtube","cancellation"],"backgroundTag":"operation-cancelled","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"}