{"record":{"id":"d55f21b5f5be2eb0","repo":"tonhowtf/omniget","slug":"download-cancelled-reddit","errorCode":null,"errorMessage":"Download cancelled","messagePattern":"Download cancelled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src-tauri/omniget-core/src/platforms/reddit.rs","lineNumber":218,"sourceCode":"            }\n        }\n        variants\n    }\n\n    async fn download_video_with_fallback(\n        &self,\n        video_url: &str,\n        output: &std::path::Path,\n        progress_tx: mpsc::Sender<ProgressUpdate>,\n        cancel: Option<&tokio_util::sync::CancellationToken>,\n    ) -> anyhow::Result<u64> {\n        let variants = Self::get_resolution_variants(video_url);\n        let mut last_err = anyhow!(\"No resolution available\");\n\n        for variant in &variants {\n            if let Some(token) = cancel {\n                if token.is_cancelled() {\n                    return Err(anyhow!(\"Download cancelled\"));\n                }\n            }\n            match direct_downloader::download_direct(\n                &self.client,\n                variant,\n                output,\n                progress_tx.clone(),\n                cancel,\n            )\n            .await\n            {\n                Ok(bytes) => return Ok(bytes),\n                Err(e) => {\n                    last_err = e;\n                    let _ = tokio::fs::remove_file(output).await;\n                }\n            }\n        }","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/reddit.rs#L200-L236","documentation":"Inside the variant loop, if a CancellationToken supplied by the caller has been cancelled, the function aborts immediately with \"Download cancelled\" instead of continuing to other resolution variants or completing the download.","triggerScenarios":"User cancels the download in the UI (or the app shuts down) while download_video_with_fallback is iterating resolution variants, and token.is_cancelled() returns true at a loop iteration boundary.","commonSituations":"User taps cancel mid-download, app window closes during a long download, or a stale/reused cancellation token is passed in when starting a new download.","solutions":["Treat this as expected control flow: catch it and show a cancelled state rather than an error.","Ensure a fresh CancellationToken is created per download instead of reusing one from a previously cancelled job.","Only cancel the token from the UI after confirming the user intends to abort.","Persist partial output cleanup on cancellation so no corrupt files remain."],"exampleFix":"// before\nif let Some(token) = cancel {\n    if token.is_cancelled() {\n        return Err(anyhow!(\"Download cancelled\"));\n    }\n}\n// after: caller-side handling as control flow, not failure\nmatch downloader.download_video_with_fallback(url, out, tx, Some(&token)).await {\n    Err(e) if e.to_string() == \"Download cancelled\" => { /* show 'cancelled', not error */ }\n    other => other?,\n}","handlingStrategy":"try-catch","validationCode":"// check token state before starting a new job\nif cancel_token.map(|t| t.is_cancelled()).unwrap_or(false) {\n    return; // do not start a download with a cancelled token\n}","typeGuard":null,"tryCatchPattern":"match download(...).await {\n    Err(e) if e.to_string() == \"Download cancelled\" => {\n        ui.set_state(JobState::Cancelled);\n        cleanup_partial_output(output);\n    }\n    Err(e) => ui.set_state(JobState::Failed(e.to_string())),\n    Ok(bytes) => ui.set_state(JobState::Done(bytes)),\n}","preventionTips":["Create a fresh CancellationToken per download job; never reuse cancelled ones.","Treat cancellation as normal control flow, not a failure state.","Clean up partial files when a download is cancelled.","Cancel tokens only from explicit user actions."],"tags":["cancellation","download","async","reddit"],"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"}