tonhowtf/omniget · info

Download cancelled

Error message

Download cancelled

What it means

The receiver's download loop polls opts.cancel_token each iteration; when the user (or caller) cancels, download deletes the partial output file and bails with "Download cancelled". This is an intentional cooperative-cancellation signal, not a fault.

Solutions

  1. No fix needed — treat as expected control flow: catch it and update UI to 'cancelled'.
  2. If it fires unexpectedly, audit who holds a clone of the cancel_token and whether anything cancels it early.
  3. If you need the partial file for resumption, copy/rename it before cancelling; the handler deletes output_path unconditionally.

Example fix

// before
// caller
if err.to_string() == "Download cancelled" { /* crash path */ }
// after
match download(opts).await {
    Err(e) if e.to_string().contains("Download cancelled") => ui.set_status("Cancelled"),
    Err(e) => ui.show_error(e),
    Ok(()) => ui.set_status("Done"),
}
Defensive patterns

Strategy: try-catch

Try / catch

match download(opts).await {
    Err(e) if e.to_string() == "Download cancelled" => ui.set_status("Cancelled"),
    Err(e) => ui.show_error(e),
    Ok(path) => ui.show_file(path),
}

Prevention

When it happens

Trigger: Caller cancels the CancellationToken passed in opts while the while received < file_size loop is reading chunks; next loop iteration detects is_cancelled(), removes output_path, and bails.

Common situations: User presses cancel in the UI, the frontend drops the transfer request, or an app-shutdown hook cancels all in-flight downloads.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/095101a8a742f73a. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/src/platforms/p2p/mod.rs:166

        write_half.write_all(b"OK\n").await?;
        write_half.flush().await?;

        let _ = progress.send(ProgressUpdate::percent(0.0)).await;

        let sanitized = sanitize_filename::sanitize(&file_name);
        let output_path = opts.output_dir.join(&sanitized);
        if let Some(parent) = output_path.parent() {
            tokio::fs::create_dir_all(parent).await?;
        }

        let mut file = File::create(&output_path).await?;
        let mut received: u64 = 0;
        let mut buf = vec![0u8; CHUNK_SIZE];

        while received < file_size {
            if opts.cancel_token.is_cancelled() {
                let _ = tokio::fs::remove_file(&output_path).await;
                anyhow::bail!("Download cancelled");
            }

            let to_read = ((file_size - received) as usize).min(CHUNK_SIZE);
            let n = reader.read(&mut buf[..to_read]).await?;
            if n == 0 {
                break;
            }

            file.write_all(&buf[..n]).await?;
            received += n as u64;

            if file_size > 0 {
                let pct = (received as f64 / file_size as f64) * 100.0;
                let _ = progress.send(ProgressUpdate::percent(pct)).await;
            }
        }

        file.flush().await?;

View on GitHub (pinned to 8600b91f42)