{"record":{"id":"a1e682646de7184c","repo":"tonhowtf/omniget","slug":"download-cancelled-p2p","errorCode":null,"errorMessage":"Download cancelled","messagePattern":"Download cancelled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src-tauri/omniget-core/src/platforms/p2p.rs","lineNumber":164,"sourceCode":"        write_half.write_all(b\"OK\\n\").await?;\n        write_half.flush().await?;\n\n        let _ = progress.send(ProgressUpdate::percent(0.0)).await;\n\n        let sanitized = sanitize_filename::sanitize(&file_name);\n        let output_path = opts.output_dir.join(&sanitized);\n        if let Some(parent) = output_path.parent() {\n            tokio::fs::create_dir_all(parent).await?;\n        }\n\n        let mut file = File::create(&output_path).await?;\n        let mut received: u64 = 0;\n        let mut buf = vec![0u8; CHUNK_SIZE];\n\n        while received < file_size {\n            if opts.cancel_token.is_cancelled() {\n                let _ = tokio::fs::remove_file(&output_path).await;\n                anyhow::bail!(\"Download cancelled\");\n            }\n\n            let to_read = ((file_size - received) as usize).min(CHUNK_SIZE);\n            let n = reader.read(&mut buf[..to_read]).await?;\n            if n == 0 {\n                break;\n            }\n\n            file.write_all(&buf[..n]).await?;\n            received += n as u64;\n\n            if file_size > 0 {\n                let pct = (received as f64 / file_size as f64) * 100.0;\n                let _ = progress.send(ProgressUpdate::percent(pct)).await;\n            }\n        }\n\n        file.flush().await?;","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/p2p.rs#L146-L182","documentation":"Thrown when the download's cancel_token is signalled while the receiver is still streaming bytes to disk. The partial output file is removed first, then this error aborts the download loop. It is the library's cooperative-cancellation mechanism, not an unexpected failure.","triggerScenarios":"Calling download() and cancelling the CancellationToken passed via DownloadOptions.cancel_token mid-transfer — e.g. the user presses a stop/cancel button in the UI.","commonSituations":"User aborts a slow P2P transfer; app shutdown cancels in-flight downloads; a UI timeout cancels a stalled transfer.","solutions":["Treat this error as an intentional user abort: filter/match on the message or use a dedicated cancellation error variant and skip generic error reporting","Don't retry automatically — the token was cancelled deliberately; re-arm a fresh cancel_token if a retry is desired","Ensure the output_path directory is writable so the partial-file cleanup succeeds"],"exampleFix":"// before\nif let Err(e) = p2p::download(&info, &opts, tx).await {\n    ui.show_error(e.to_string());\n}\n// after\nif let Err(e) = p2p::download(&info, &opts, tx).await {\n    if e.to_string().contains(\"Download cancelled\") {\n        ui.show_info(\"Transfer cancelled by user\");\n    } else {\n        ui.show_error(e.to_string());\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Ensure a fresh token per download and that it is not already cancelled\nif opts.cancel_token.is_cancelled() {\n    anyhow::bail!(\"Cancel token already triggered before download started\");\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = p2p::download(&info, &opts, tx).await {\n    if e.to_string().contains(\"Download cancelled\") {\n        // expected user abort: clean up UI state, no error toast\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["Use one cancel token per user action; never share tokens across downloads","Clean partial output files on any download error","Distinguish cancellation from failure in UI copy"],"tags":["p2p","cancellation","download","control-flow"],"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"}