libnyanpasu/clash-nyanpasu · error
download failed: {e}
Error message
download failed: {e} What it means
Returned by `DownloadSession::start` when the task was started successfully but `task.wait()` later reports the transfer failed. Before returning, the session's state is set to `DownloaderState::Failed(e.to_string())`, so the failure reason is persisted in `status()` as well. This is the mid-transfer failure path: network errors, server errors, checksum/IO failures during download.
Source
Thrown at backend/tauri/src/core/download/mod.rs:133
.build()
.await
.map_err(|e| anyhow::anyhow!("failed to build download task: {e}"))?;
Ok(Self {
inner,
task: Mutex::new(task),
})
}
pub async fn start(&self) -> anyhow::Result<()> {
let mut task = self.task.lock().await;
task.run()
.await
.map_err(|e| anyhow::anyhow!("failed to start download: {e}"))?;
match task.wait().await {
Ok(()) => Ok(()),
Err(e) => {
*self.inner.state.write() = DownloaderState::Failed(e.to_string());
Err(anyhow::anyhow!("download failed: {e}"))
}
}
}
pub fn status(&self) -> DownloadStatus {
let prog = *self.inner.progress.read();
DownloadStatus {
state: self.inner.state.read().clone(),
downloaded: prog.downloaded,
total: prog.total,
speed: prog.speed,
}
}
#[allow(dead_code)]
pub fn cancel(&self) {
self.inner.cancel.cancel();
}View on GitHub (pinned to f7dbce2997)
Solutions
- Inspect `{e}` and `status()` to learn the failure cause; fix the specific issue (URL, network, disk).
- Retry the download with a new session, ideally with backoff for transient network/server errors.
- Verify the URL is reachable (curl -I) and the target still exists (core binaries move between releases).
- Check free disk space and write permissions on save_path.
- If behind a proxy/firewall, configure the reqwest client's proxy settings.
Example fix
// before
session.start().await?;
// after
match session.start().await {
Ok(()) => {}
Err(e) => {
log::warn!("download failed: {e:#}, retrying...");
tokio::time::sleep(Duration::from_secs(5)).await;
let session = DownloadSession::new(client, url, save_path).await?;
session.start().await?;
}
} Defensive patterns
Strategy: retry
Validate before calling
// preflight the URL before downloading
let head = client.head(url.as_str()).send().await?;
if !head.status().is_success() {
anyhow::bail!("URL unreachable: HTTP {}", head.status());
} Try / catch
match session.start().await {
Ok(()) => Ok(()),
Err(e) if is_transient(&e) => retry_with_backoff(|| async {
DownloadSession::new(client.clone(), url.clone(), save_path.clone()).await?
.start().await
}),
Err(e) => Err(e),
} Prevention
- Retry with a fresh session and exponential backoff for transient network/HTTP errors
- Read status().state (Failed carries the reason) before deciding the retry policy
- Preflight the URL with a HEAD request; core download URLs change between releases
- Check disk space and save-path writability before starting
- Configure reqwest proxy/timeouts appropriately for restricted networks
When it happens
Trigger: Calling `start()` and the download ultimately fails — HTTP errors from the server (4xx/5xx), connection resets/timeouts, disk full or write error while saving, cancelled-by-remote, or any error surfaced by the download crate's `wait()`.
Common situations: Unstable network or VPN drops mid-download; GitHub/CDN returning 403/404/502 for core or geo-data downloads; disk quota exceeded; server closing connection before completion; TLS/proxy interception.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- failed to build download task: {e}
- failed to start download: {e}
- failed to read PAC script content: {}
- failed to download PAC script, status: {}
- no mirrors found
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/d7062d1a882c2549.
Report an issue: GitHub.