{"record":{"id":"6e6f2a05f32c2887","repo":"tonhowtf/omniget","slug":"spawn-blocking-failed-pdfium","errorCode":null,"errorMessage":"spawn_blocking failed: {}","messagePattern":"spawn_blocking failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/pdfium.rs","lineNumber":202,"sourceCode":"        ));\n    }\n    let bytes = response.bytes().await?.to_vec();\n    if bytes.len() < 100_000 {\n        return Err(anyhow!(\n            \"Downloaded pdfium archive is too small ({} bytes) — likely an error page\",\n            bytes.len()\n        ));\n    }\n\n    let target_path_clone = target_path.clone();\n    let target_dir_clone = target_dir.clone();\n    let lib_name = lib_filename.to_string();\n    let extracted_version =\n        tokio::task::spawn_blocking(move || -> anyhow::Result<Option<String>> {\n            extract_pdfium_archive(&bytes, &target_path_clone, &target_dir_clone, &lib_name)\n        })\n        .await\n        .map_err(|e| anyhow!(\"spawn_blocking failed: {}\", e))??;\n\n    if let Some(version_marker) = pdfium_version_marker_path() {\n        let base = extracted_version.unwrap_or_else(|| \"latest\".to_string());\n        let value = format!(\"{} ({})\", base, archive_name);\n        let _ = std::fs::write(&version_marker, value);\n    }\n\n    #[cfg(target_os = \"macos\")]\n    {\n        let _ = tokio::task::spawn_blocking({\n            let p = target_path.clone();\n            move || {\n                crate::core::process::std_command(\"xattr\")\n                    .args([\"-d\", \"com.apple.quarantine\"])\n                    .arg(&p)\n                    .output()\n            }\n        })","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/pdfium.rs#L184-L220","documentation":"The archive extraction runs off the async runtime via tokio::task::spawn_blocking. If the blocking task itself panics (or the runtime is shutting down), the JoinHandle resolves to a JoinError and this error wraps it. Note the double `??`: this error covers the join failure, while extraction I/O errors surface separately with their own messages.","triggerScenarios":"extract_pdfium_archive panics inside the blocking thread (e.g. unwrap on bad zip entry, OOM during decompression) or the tokio runtime is being dropped while the task runs.","commonSituations":"Corrupt or maliciously crafted archive triggering a panic in the zip decoder; app shutdown cancelling in-flight installation; runtime built without blocking-thread budget.","solutions":["Read the wrapped panic message from the error chain to find the panicking operation in extract_pdfium_archive","Test extraction against the exact downloaded archive to reproduce the panic","Replace panicking unwraps/expects in extract_pdfium_archive with proper anyhow errors","Retry the installation when the cause was runtime shutdown during app exit"],"exampleFix":"// before\nlet name = entry.mangled_name().unwrap();\n// after\nlet name = entry.mangled_name()\n    .map_err(|e| anyhow!(\"bad archive entry name: {}\", e))?;","handlingStrategy":"try-catch","validationCode":"// validate the archive before extraction\nlet cursor = std::io::Cursor::new(&bytes);\nlet mut zip = zip::ZipArchive::new(cursor)?; // Err here = corrupt archive\nzip.by_index(0)?;","typeGuard":null,"tryCatchPattern":"match ensure_pdfium().await {\n    Err(e) if e.to_string().contains(\"spawn_blocking failed\") => {\n        // blocking task panicked; inspect the wrapped panic text and re-download\n    }\n    other => other.map(|_| ()),\n}","preventionTips":["Replace unwrap/expect in extract_pdfium_archive with anyhow errors so failures aren't panics","Validate the zip opens before spawning the blocking task","Avoid cancelling installation during app shutdown; await the in-flight task"],"tags":["rust","tokio","async","panic"],"backgroundTag":"thread-interrupted","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}