{"record":{"id":"ed68d921002a1cde","repo":"Zackriya-Solutions/meetily","slug":"failed-to-read-downloaded-model-file-metadata","errorCode":null,"errorMessage":"Failed to read downloaded model file metadata: {}","messagePattern":"Failed to read downloaded model file metadata: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"frontend/src-tauri/src/whisper_engine/whisper_engine.rs","lineNumber":985,"sourceCode":"\n        if result.is_ok() && !active_download.cancellation.is_cancelled() {\n            result = self.validate_model_file(file_path).await;\n\n            if result.is_ok() {\n                let expected_min_size = WHISPER_MODEL_CATALOG\n                    .iter()\n                    .find(|model| model.0 == model_name)\n                    .map(|model| ((model.2 as f64 * 0.9) as u64) * 1024 * 1024);\n\n                result = match expected_min_size {\n                    Some(expected_min_size) => match fs::metadata(file_path).await {\n                        Ok(metadata) if metadata.len() >= expected_min_size => Ok(()),\n                        Ok(metadata) => Err(anyhow!(\n                            \"Downloaded model file is too small: {} bytes (expected at least {} bytes)\",\n                            metadata.len(),\n                            expected_min_size\n                        )),\n                        Err(e) => Err(anyhow!(\n                            \"Failed to read downloaded model file metadata: {}\",\n                            e\n                        )),\n                    },\n                    None => Err(anyhow!(\n                        \"Unsupported model for download validation: {}\",\n                        model_name\n                    )),\n                };\n            }\n        }\n\n        if result.is_err() && !active_download.cancellation.is_cancelled() && file_path.exists() {\n            if let Err(e) = fs::remove_file(file_path).await {\n                log::warn!(\"Failed to clean up failed download file: {}\", e);\n            } else {\n                log::info!(\"Cleaned up failed download file: {}\", file_path.display());\n            }","sourceCodeStart":967,"sourceCodeEnd":1003,"githubUrl":"https://github.com/Zackriya-Solutions/meetily/blob/a2cb62e827da7ef59f65064c97233efb2313878e/frontend/src-tauri/src/whisper_engine/whisper_engine.rs#L967-L1003","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before: stat may race with concurrent cleanup/delete\nlet result = match fs::metadata(file_path).await {\n    Ok(m) if m.len() >= expected_min_size => Ok(()),\n    Ok(m) => Err(anyhow!(\"too small: {}\", m.len())),\n    Err(e) => Err(anyhow!(\"Failed to read downloaded model file metadata: {}\", e)),\n};\n// after: retry once and tolerate a racing delete by falling back to read-based size\nlet result = match fs::metadata(file_path).await.or_else(|_| fs::metadata(file_path).await) {\n    Ok(m) if m.len() >= expected_min_size => Ok(()),\n    Ok(m) => Err(anyhow!(\"Downloaded model file is too small: {} bytes (expected at least {} bytes)\", m.len(), expected_min_size)),\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound =>\n        Err(anyhow!(\"Downloaded model file disappeared before validation: {}\", file_path.display())),\n    Err(e) => Err(anyhow!(\"Failed to read downloaded model file metadata: {}\", e)),\n};","handlingStrategy":"try-catch","validationCode":"let path = models_dir.join(format!(\"ggml-{}.bin\", model_name));\nif !models_dir.exists() {\n    return Err(\"models directory is missing or unmounted\");\n}\nif let Err(e) = tokio::fs::metadata(&path).await {\n    eprintln!(\"pre-flight stat of {} failed: {}\", path.display(), e);\n}","typeGuard":"fn is_stat_likely_ok(path: &std::path::Path) -> bool {\n    path.parent().map(|p| p.is_dir()).unwrap_or(false)\n        && path\n            .file_name()\n            .and_then(|n| n.to_str())\n            .map(|n| !n.is_empty() && n.len() < 255)\n            .unwrap_or(false)\n}","tryCatchPattern":"match download_result {\n    Err(e) if e.to_string().contains(\"Failed to read downloaded model file metadata\") => {\n        // transient stat failure: verify no AV/cloud-sync interference, then retry once\n        cleanup_partial_file(&path);\n        retry_download(model_name, 1).await\n    }\n    Err(e) => Err(e),\n    Ok(()) => Ok(()),\n}","preventionTips":["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."],"tags":["filesystem","io","model-download","rust","whisper"],"backgroundTag":"file-read-failed","analyzedSha":"a2cb62e827da7ef59f65064c97233efb2313878e","analyzedAt":"2026-09-12T11:12:14.152Z","contentChangedAt":"2026-09-12T11:12:14.152Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}