{"record":{"id":"339f753fdd96cddc","repo":"cjpais/Handy","slug":"sha256-task-panicked","errorCode":null,"errorMessage":"SHA256 task panicked: {}","messagePattern":"SHA256 task panicked: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/src/managers/model/download.rs","lineNumber":117,"sourceCode":"        Ok(format!(\"{:x}\", hasher.finalize()))\n    }\n\n    /// Emit verification events around a blocking sha256 check of `path`.\n    /// On mismatch `verify_sha256` deletes the file, so the next attempt (or\n    /// next source) starts clean. A `None` hash skips checking (custom models).\n    async fn verify_file_with_events(\n        model_id: &str,\n        path: &Path,\n        expected_sha256: Option<&str>,\n        emit: &(dyn Fn(HttpDownloadEvent<'_>) + Send + Sync),\n    ) -> Result<()> {\n        emit(HttpDownloadEvent::VerificationStarted);\n        let path = path.to_path_buf();\n        let expected = expected_sha256.map(str::to_string);\n        let id = model_id.to_string();\n        tokio::task::spawn_blocking(move || Self::verify_sha256(&path, expected.as_deref(), &id))\n            .await\n            .map_err(|e| anyhow::anyhow!(\"SHA256 task panicked: {}\", e))??;\n        emit(HttpDownloadEvent::VerificationCompleted);\n        Ok(())\n    }\n\n    /// [`Self::download_http_resumable_with_events`] wired to the Tauri event\n    /// bus — the production entry point.\n    pub(super) async fn download_http_resumable(\n        &self,\n        model_id: &str,\n        url: &str,\n        partial_path: &Path,\n        expected_size: Option<u64>,\n        expected_sha256: Option<&str>,\n        cancel_token: &CancellationToken,\n    ) -> Result<HttpDownloadOutcome> {\n        let app_handle = self.app_handle.clone();\n        let id = model_id.to_string();\n        Self::download_http_resumable_with_events(","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/cjpais/Handy/blob/c89b7bf38974ad317177389f5bfe28236f0d64e3/src-tauri/src/managers/model/download.rs#L99-L135","documentation":"Raised when the tokio::task::spawn_blocking job that runs verify_sha256 comes back with a JoinError, meaning the blocking task panicked or was aborted instead of returning a result. Because the hasher code itself mostly returns Err on I/O problems, a panic usually indicates the file was removed underneath the task, or the runtime is shutting down and cancelled the blocking task. The double '?' maps the JoinError into this anyhow message.","triggerScenarios":"verify_file_with_events races: the task panics while hashing (e.g., path metadata invalidated), or the tokio runtime is being torn down (app quit) and the JoinHandle is cancelled, yielding JoinError::cancelled.","commonSituations":"User cancels/quits during post-download verification; a second instance or cleanup process deletes the partial; bugs where the download state machine drops the future mid-verification.","solutions":["Retry the download — verification runs again at the end.","Avoid deleting or touching the models directory while a download/verification is in flight.","If it happens on every quit-during-download, let the download finish or cancel through the app's own cancel flow rather than killing the process.","Check logs for the panic backtrace (RUST_BACKTRACE=1) if it occurs without cancellation — that indicates a real bug worth reporting."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match manager.download_model(model_id, None).await {\n    Ok(_) => Ok(()),\n    Err(e) if e.to_string().contains(\"SHA256 task panicked\") => {\n        // blocking task died (often shutdown race); a full retry is safe\n        manager.download_model(model_id, None).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Cancel downloads through the app's cancel flow so the runtime isn't torn down mid-verification.","Never delete partials from outside the app while a download is running.","Run with RUST_BACKTRACE=1 in dev to capture the underlying panic if it happens outside shutdown."],"tags":["tokio","spawn-blocking","panic","sha256","verification"],"backgroundTag":"background-task-panicked","analyzedSha":"c89b7bf38974ad317177389f5bfe28236f0d64e3","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}