tonhowtf/omniget · info · anyhow::Error
Download cancelled by user
Error message
Download cancelled by user
What it means
download_with_quality checks the caller-supplied CancellationToken before doing any work and immediately bails if cancellation was already requested. The library surfaces cooperative cancellation as a regular anyhow error rather than a panic or silent no-op, so callers can distinguish user-aborted downloads from network failures.
Solutions
- Treat this error as an expected outcome: catch it and skip retry logic, since the user asked to cancel.
- If the download should proceed, create a fresh (non-cancelled) CancellationToken for the attempt instead of reusing an already-cancelled one.
- Check token.is_cancelled() before spawning the download task to avoid starting work that will be rejected.
- If the cancel was accidental (e.g. watchdog fired early), fix the cancellation trigger's timing before re-invoking download().
Example fix
// before let token = shared_token.clone(); shared_token.cancel(); // watchdog fired earlier hls.download(url, quality, token).await?; // -> "Download cancelled by user" // after let token = CancellationToken::new(); // fresh token for a new attempt hls.download(url, quality, token).await?;
Defensive patterns
Strategy: try-catch
Validate before calling
if cancel_token.is_cancelled() {
// skip starting the download at all
return;
} Try / catch
match hls.download(url, quality, token.clone()).await {
Ok(res) => handle_result(res),
Err(e) if e.to_string() == "Download cancelled by user" => {
// expected: no retry, update UI to 'cancelled'
},
Err(e) => retry_or_report(e),
} Prevention
- Issue a fresh CancellationToken for each download attempt.
- Check is_cancelled() before enqueueing a download task.
- Never reuse a token that a previous operation already cancelled.
- Distinguish cancellation errors from real failures in your retry logic.
When it happens
Trigger: Calling download() -> download_with_quality with a CancellationToken on which cancel() was already invoked (e.g. the UI fired a cancel while the task was still being spawned), or a token that some other component cancelled before the download started.
Common situations: User clicks Cancel in the app at nearly the same moment the download task is enqueued; a timeout watchdog cancels the token just before the worker starts; reusing a single token across sequential downloads without resetting it.
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
- Send cancelled while waiting for receiver
- Send cancelled while paused
- Download cancelled
- Download cancelled
- Download cancelled during session creation
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/79d33d929c77fc9e.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/hls_downloader.rs:143
None,
)
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn download_with_quality(
&self,
m3u8_url: &str,
output_path: &str,
referer: &str,
bytes_tx: Option<UnboundedSender<u64>>,
cancel_token: CancellationToken,
max_concurrent: u32,
max_retries: u32,
max_height: Option<u32>,
) -> anyhow::Result<HlsDownloadResult> {
if cancel_token.is_cancelled() {
anyhow::bail!("Download cancelled by user");
}
let m3u8_text = self.fetch_m3u8_with_retry(m3u8_url, referer, 3).await?;
let m3u8_bytes = m3u8_text.as_bytes();
if let Ok((_, master)) = parse_master_playlist(m3u8_bytes) {
if let Some(variant) = select_best_variant(&master, max_height) {
let available: Vec<u64> = master
.variants
.iter()
.filter(|v| !v.is_i_frame)
.map(variant_height)
.collect();
tracing::info!(
"[hls] variant selected: {}p (requested: {}, available: {:?})",
variant_height(variant),
max_heightView on GitHub (pinned to 8600b91f42)