{"record":{"id":"e16c44d0ea20bf44","repo":"tonhowtf/omniget","slug":"spawn-blocking-failed-dependencies","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/dependencies.rs","lineNumber":430,"sourceCode":"\n    for (url, archive_type) in downloads {\n        tracing::info!(\"Downloading FFmpeg component from {}\", url);\n        let response = client.get(url).send().await?;\n        if !response.status().is_success() {\n            return Err(anyhow!(\n                \"Failed to download FFmpeg from {}: HTTP {}\",\n                url,\n                response.status()\n            ));\n        }\n\n        let temp_path = bin_dir.join(\".ffmpeg_download.tmp\");\n        let bytes = response.bytes().await?;\n        let data = bytes.to_vec();\n        let temp_clone = temp_path.clone();\n        tokio::task::spawn_blocking(move || std::fs::write(&temp_clone, &data))\n            .await\n            .map_err(|e| anyhow!(\"spawn_blocking failed: {}\", e))??;\n\n        let file_size = std::fs::metadata(&temp_path)?.len();\n        if file_size < 1_000_000 {\n            let _ = std::fs::remove_file(&temp_path);\n            return Err(anyhow!(\n                \"Downloaded file from {} is too small ({}B) — likely an error page\",\n                url,\n                file_size\n            ));\n        }\n\n        match archive_type {\n            ArchiveType::Zip => {\n                extract_zip_ffmpeg(&temp_path, &bin_dir, &ffmpeg_name, &ffprobe_name).await?\n            }\n            ArchiveType::TarXz => {\n                extract_tar_xz_ffmpeg(&temp_path, &bin_dir, &ffmpeg_name, &ffprobe_name).await?\n            }","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/dependencies.rs#L412-L448","documentation":"The blocking file-write of the downloaded FFmpeg archive is offloaded via tokio::task::spawn_blocking. If the JoinHandle resolves to a JoinError — the blocking task panicked (e.g. I/O thread panic) or the runtime is shutting down — this anyhow error wraps it. Note the extra ? after map_err propagates the inner std::io::Error separately.","triggerScenarios":"The closure moved into spawn_blocking panics (unwinding inside std::fs::write path handling) or the tokio runtime is being dropped while the blocking task is queued/running.","commonSituations":"Application shutdown mid-download; a panic in the blocking worker (rare, e.g. path issues); calling download_ffmpeg outside a live tokio runtime context.","solutions":["Check application logs for a panic inside the spawn_blocking closure at the same timestamp","Ensure the tokio runtime is alive for the duration of the download (don't drop/shutdown mid-await)","Retry the download; the error is usually transient if caused by shutdown","Avoid calling ensure_ffmpeg/update_ffmpeg during app teardown"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match download_ffmpeg().await {\n    Ok(p) => ...,\n    Err(e) if e.to_string().contains(\"spawn_blocking failed\") => {\n        eprintln!(\"blocking task panicked or runtime shutdown: {e}\");\n    }\n    Err(e) => ...,\n}","preventionTips":["Keep the tokio runtime alive for the whole install flow","Avoid panicking code paths inside the spawn_blocking closure","Don't trigger installs during app shutdown","Add a retry around transient JoinError cases"],"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"}