cjpais/Handy · error · anyhow::Error
Download verification failed for model {}: file is corrupt.
Error message
Download verification failed for model {}: file is corrupt. Please retry. What it means
After an HTTP download completes, the file's SHA256 is computed in 64KB chunks and compared against the catalog's pinned hash. A mismatch means the bytes on disk are not the published model — a corrupt transfer, a tampered or misbehaving mirror, or a catalog hash that no longer matches a re-published upstream file. The file is deleted and the caller is told to retry.
Source
Thrown at src-tauri/src/managers/model/download.rs:71
/// On mismatch or read error the partial file is deleted and an error is returned,
/// so the next download attempt always starts from a clean state.
/// When `expected_sha256` is `None` (custom user models) verification is skipped.
fn verify_sha256(path: &Path, expected_sha256: Option<&str>, model_id: &str) -> Result<()> {
let Some(expected) = expected_sha256 else {
return Ok(());
};
match Self::compute_sha256(path) {
Ok(actual) if actual == expected => {
info!("SHA256 verified for model {}", model_id);
Ok(())
}
Ok(actual) => {
warn!(
"SHA256 mismatch for model {}: expected {}, got {}",
model_id, expected, actual
);
let _ = fs::remove_file(path);
Err(anyhow::anyhow!(
"Download verification failed for model {}: file is corrupt. Please retry.",
model_id
))
}
Err(e) => {
let _ = fs::remove_file(path);
Err(anyhow::anyhow!(
"Failed to verify download for model {}: {}. Please retry.",
model_id,
e
))
}
}
}
/// Computes the SHA256 hex digest of a file, reading in 64KB chunks to handle large models.
fn compute_sha256(path: &Path) -> Result<String> {
let mut file = File::open(path)?;View on GitHub (pinned to 98a4d80cce)
Solutions
- Retry download_model — a fresh transfer often resolves transient corruption
- If it persists, verify the catalog's sha256 against the publisher (e.g. the HF repo's LFS sha256) and update the catalog
- Bypass the misbehaving mirror and use the official HuggingFace source
- Check disk health and free space; disable interfering proxies
Example fix
// before
let outcome = downloader.download_http_resumable(...).await?;
// after — corrupt file is deleted by the verifier; a fresh attempt is safe
let mut attempt = 0;
let outcome = loop {
attempt += 1;
match downloader.download_http_resumable(...).await {
Ok(o) => break o,
Err(e) if e.to_string().contains("file is corrupt") && attempt < 3 => continue,
Err(e) => return Err(e),
}
}; Defensive patterns
Strategy: retry
Validate before calling
// Before reusing an already-downloaded file, verify it against the pinned hash
fn model_file_intact(path: &Path, expected_sha256: Option<&str>) -> bool {
match expected_sha256 {
Some(expected) => ModelDownload::compute_sha256(path)
.map(|actual| actual == expected)
.unwrap_or(false),
None => true, // no pinned hash — nothing to validate against
}
} Try / catch
let mut attempts = 0;
loop {
attempts += 1;
match downloader.download_http_resumable(...).await {
Ok(outcome) => break Ok(outcome),
Err(e) if e.to_string().contains("file is corrupt") && attempts < 3 => {
// verifier already deleted the corrupt file; retry clean
continue;
}
Err(e) => break Err(e),
}
} Prevention
- Pin a sha256 for every catalog entry — it is the trust anchor for mirror downloads
- Prefer official HuggingFace sources over third-party mirrors for integrity guarantees
- Surface the retry affordance to the user; corrupt-transfers are usually transient
When it happens
Trigger: A mirror host serving wrong or padded content that still matches the expected size; a TLS-terminating proxy corrupting bytes; upstream re-published the file while the catalog still pins the old sha256; disk corruption during the write.
Common situations: Custom mirror URLs that go stale when a model is updated upstream; flaky transfers where size checks pass but content differs; catalog/app version skew after a model re-release.
Related errors
- Failed to verify download for model {}: {}. Please retry.
- SHA256 task panicked: {}
- server sent more than the expected {} bytes
AI-assisted analysis of cjpais/Handy@98a4d80cce (2026-08-16).
Data as JSON: /api/errors/5bcfa3445f75b4e9.
Report an issue: GitHub.