{"record":{"id":"36a22ac4865c381d","repo":"tonhowtf/omniget","slug":"download-cancelled-course-utils","errorCode":null,"errorMessage":"Download cancelled","messagePattern":"Download cancelled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src-tauri/omniget-core/src/core/course_utils.rs","lineNumber":74,"sourceCode":"            .and_then(|e| e.split('?').next())\n            .filter(|e| e.len() <= 5)\n            .unwrap_or(\"bin\");\n        format!(\"attachment.{}\", ext)\n    } else {\n        sanitized\n    };\n\n    let path = format!(\"{}/{}\", dir, filename);\n\n    if Path::new(&path).exists() {\n        let meta = std::fs::metadata(&path);\n        if meta.map(|m| m.len() > 0).unwrap_or(false) {\n            return Ok(0);\n        }\n    }\n\n    if cancel_token.is_cancelled() {\n        return Err(anyhow!(\"Download cancelled\"));\n    }\n\n    let resp = client\n        .get(url)\n        .send()\n        .await\n        .map_err(|e| anyhow!(\"Failed to download attachment: {}\", e))?;\n\n    if !resp.status().is_success() {\n        return Err(anyhow!(\n            \"Attachment download failed: HTTP {}\",\n            resp.status()\n        ));\n    }\n\n    let bytes = resp.bytes().await?;\n    let size = bytes.len() as u64;\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/course_utils.rs#L56-L92","documentation":"download_attachment checks a cooperative cancellation token before issuing the HTTP GET for an attachment. If cancel_token.is_cancelled() is true, it aborts with \"Download cancelled\". This is a normal, expected control-flow error used to stop in-flight or queued attachment downloads.","triggerScenarios":"The user (or application logic) cancels a course/attachment download — cancel_token.cancel() is called on the shared CancellationToken while download_attachment is running or about to start; the next is_cancelled() check at course_utils.rs:74 returns true before the request is sent.","commonSituations":"User pressing a cancel/stop button in the download UI; app shutdown while downloads are queued; a parent download manager cancelling all per-attachment tokens when the overall task is aborted.","solutions":["Treat this error as an expected outcome: catch it and update the UI to 'cancelled' rather than showing it as a failure.","If downloads are being cancelled unintentionally, audit where cancel_token.cancel() is called (timeout handlers, task aborts, parent cancellation).","Re-issue the download with a fresh (non-cancelled) token if the cancellation was spurious.","Filter this specific message out of generic error reporting paths so it does not surface as a crash log."],"exampleFix":"// before\nmatch download_attachment(&client, &url, &dest, &token).await {\n    Err(e) => log::error!(\"attachment failed: {}\", e),\n    Ok(n) => log::info!(\"downloaded {} bytes\", n),\n}\n\n// after\nmatch download_attachment(&client, &url, &dest, &token).await {\n    Err(e) if e.to_string().contains(\"Download cancelled\") => log::info!(\"attachment download cancelled by user\"),\n    Err(e) => log::error!(\"attachment failed: {}\", e),\n    Ok(n) => log::info!(\"downloaded {} bytes\", n),\n}","handlingStrategy":"try-catch","validationCode":"// Check the token before starting so work is skipped cheaply\nif cancel_token.is_cancelled() {\n    return Ok(0); // or skip the attachment entirely\n}","typeGuard":null,"tryCatchPattern":"match download_attachment(&client, &url, &dest, &token).await {\n    Err(e) if e.to_string() == \"Download cancelled\" => {\n        log::info!(\"skipped (cancelled): {}\", url);\n        Ok(0)\n    }\n    other => other.map(|_| ()),\n}","preventionTips":["Treat cancellation as a normal outcome, not a failure","Model cancellation with a typed enum instead of string matching where possible","Cancel tokens deterministically and document where cancel() is called","Update download UI state to 'cancelled' on this error"],"tags":["download","cancellation","control-flow","async"],"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"}