Zackriya-Solutions/meetily · error · anyhow::Error
Failed to read downloaded model file metadata: {}
Error message
Failed to read downloaded model file metadata: {} What it means
During post-download validation, finish_download calls fs::metadata(file_path) on the freshly downloaded model file. If that metadata read fails (std::io::Error), the download is treated as failed and this anyhow error wraps the underlying OS error. It means the app downloaded bytes but cannot stat the resulting file, so the size sanity check cannot run. The partial file is then deleted and the model status is reset to Missing.
Source
Thrown at frontend/src-tauri/src/whisper_engine/whisper_engine.rs:985
if result.is_ok() && !active_download.cancellation.is_cancelled() {
result = self.validate_model_file(file_path).await;
if result.is_ok() {
let expected_min_size = WHISPER_MODEL_CATALOG
.iter()
.find(|model| model.0 == model_name)
.map(|model| ((model.2 as f64 * 0.9) as u64) * 1024 * 1024);
result = match expected_min_size {
Some(expected_min_size) => match fs::metadata(file_path).await {
Ok(metadata) if metadata.len() >= expected_min_size => Ok(()),
Ok(metadata) => Err(anyhow!(
"Downloaded model file is too small: {} bytes (expected at least {} bytes)",
metadata.len(),
expected_min_size
)),
Err(e) => Err(anyhow!(
"Failed to read downloaded model file metadata: {}",
e
)),
},
None => Err(anyhow!(
"Unsupported model for download validation: {}",
model_name
)),
};
}
}
if result.is_err() && !active_download.cancellation.is_cancelled() && file_path.exists() {
if let Err(e) = fs::remove_file(file_path).await {
log::warn!("Failed to clean up failed download file: {}", e);
} else {
log::info!("Cleaned up failed download file: {}", file_path.display());
}View on GitHub (pinned to a2cb62e827)
Solutions
- Check the models directory still exists and is on a local, mounted, writable volume before downloading (UI shows the path in model settings).
- Exclude the Meetily models directory from antivirus/EDR real-time scanning or quarantine of large .bin files.
- Verify nothing else (another app instance, cloud-sync like Dropbox/OneDrive) is managing or deleting files in the models folder.
- Retry the download — transient stat failures (racing cleanup, brief unmount) usually succeed on a second attempt.
- If reproducible, inspect the wrapped io::Error in the message ('{}' suffix) for the concrete OS reason (NOENT, PERMISSION_DENIED, etc.) and fix that root cause.
Example fix
// before: stat may race with concurrent cleanup/delete
let result = match fs::metadata(file_path).await {
Ok(m) if m.len() >= expected_min_size => Ok(()),
Ok(m) => Err(anyhow!("too small: {}", m.len())),
Err(e) => Err(anyhow!("Failed to read downloaded model file metadata: {}", e)),
};
// after: retry once and tolerate a racing delete by falling back to read-based size
let result = match fs::metadata(file_path).await.or_else(|_| fs::metadata(file_path).await) {
Ok(m) if m.len() >= expected_min_size => Ok(()),
Ok(m) => Err(anyhow!("Downloaded model file is too small: {} bytes (expected at least {} bytes)", m.len(), expected_min_size)),
Err(e) if e.kind() == std::io::ErrorKind::NotFound =>
Err(anyhow!("Downloaded model file disappeared before validation: {}", file_path.display())),
Err(e) => Err(anyhow!("Failed to read downloaded model file metadata: {}", e)),
}; Defensive patterns
Strategy: try-catch
Validate before calling
let path = models_dir.join(format!("ggml-{}.bin", model_name));
if !models_dir.exists() {
return Err("models directory is missing or unmounted");
}
if let Err(e) = tokio::fs::metadata(&path).await {
eprintln!("pre-flight stat of {} failed: {}", path.display(), e);
} Type guard
fn is_stat_likely_ok(path: &std::path::Path) -> bool {
path.parent().map(|p| p.is_dir()).unwrap_or(false)
&& path
.file_name()
.and_then(|n| n.to_str())
.map(|n| !n.is_empty() && n.len() < 255)
.unwrap_or(false)
} Try / catch
match download_result {
Err(e) if e.to_string().contains("Failed to read downloaded model file metadata") => {
// transient stat failure: verify no AV/cloud-sync interference, then retry once
cleanup_partial_file(&path);
retry_download(model_name, 1).await
}
Err(e) => Err(e),
Ok(()) => Ok(()),
} Prevention
- Keep models on a local, always-mounted disk; avoid network shares and removable drives for the models directory.
- Whitelist the models directory in antivirus/EDR and exclude it from cloud-sync tools.
- Avoid running multiple app instances sharing one models directory.
- Log the wrapped io::Error kind to distinguish NotFound (deleted file) from PermissionDenied (AV/ACL) early.
When it happens
Trigger: fs::metadata() on the just-written models_dir/ggml-<name>.bin returns Err — e.g. the file was deleted or moved by another process/cleanup between the last write and validation, the file handle/locking on Windows blocks stat, path-too-long or invalid characters in the models dir, or the volume went offline (unmounted external drive, network share drop).
Common situations: User or antivirus quarantines/deletes the large .bin right as download finishes; models directory points at a removable/network drive that disconnects mid-download; another download/cancel task removes the file concurrently (finish_download deletes failed files); permission or filesystem corruption prevents stat.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to create file {}: {}
- Failed to flush file {}: {}
- Failed to create file: {}
- Model {} has error: {}
- Model {} is corrupted and cannot be loaded
AI-assisted analysis of Zackriya-Solutions/meetily@a2cb62e827 (2026-09-12).
Data as JSON: /api/errors/ed68d921002a1cde.
Report an issue: GitHub.