tonhowtf/omniget · error · anyhow::Error

Spawn blocking failed

Error message

Spawn blocking failed: {}

What it means

extract_zip_ffmpeg runs its blocking zip-extraction work with tokio::task::spawn_blocking. If the JoinHandle awaits to an Err (task panicked or the runtime was shut down), the error is wrapped as 'Spawn blocking failed' and propagated. The double '??' then re-raises the inner anyhow::Error if the closure itself failed.

Solutions

  1. Check logs for the inner panic backtrace and fix the root cause (permissions, disk space)
  2. Ensure File::create/copy errors inside the closure are mapped to anyhow::Error instead of panicking
  3. Do not drop/terminate the tokio runtime while spawn_blocking is pending
  4. Re-run the operation after resolving the environment issue

Example fix

// before
let mut out = std::fs::File::create(&dest)?; // panics nowhere but propagates as Err -> JoinError only on panic
// after
let mut out = std::fs::File::create(&dest)
    .map_err(|e| anyhow!("Failed to create {}: {}", dest.display(), e))?;
Defensive patterns

Strategy: try-catch

Try / catch

match tokio::task::spawn_blocking(move || extract()).await {
    Ok(Ok(())) => {},
    Ok(Err(e)) => return Err(e),
    Err(join_err) => {
        eprintln!("extraction task panicked: {join_err}");
        // retry once in a fresh blocking task after fixing env
    }
}

Prevention

When it happens

Trigger: The extraction closure panics (e.g. File::create unwrap-style failure inside, index panic, unzip path traversal panic) while the async runtime is active; tokio runtime shutdown during await; blocking pool starvation causing cancellation.

Common situations: A panic in File::create/copy due to permission-denied or disk-full inside the closure; app shutting down while ffmpeg install runs; running under a current-thread runtime that drops the blocking task.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/b44ffb32813c0631. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/dependencies.rs:609

            let mut entry = archive
                .by_index(i)
                .map_err(|e| anyhow!("Failed to read zip entry: {}", e))?;

            let name = entry.name().to_string();
            for target in &targets {
                if name.ends_with(target) {
                    let dest = bin_dir.join(format!("{}.new", target));
                    let mut out = std::fs::File::create(&dest)?;
                    std::io::copy(&mut entry, &mut out)?;
                    break;
                }
            }
        }

        Ok::<(), anyhow::Error>(())
    })
    .await
    .map_err(|e| anyhow!("Spawn blocking failed: {}", e))??;

    Ok(())
}

async fn extract_tar_xz_ffmpeg(
    archive_path: &std::path::Path,
    bin_dir: &std::path::Path,
    ffmpeg_name: &str,
    ffprobe_name: &str,
) -> anyhow::Result<()> {
    let archive_path = archive_path.to_path_buf();
    let bin_dir = bin_dir.to_path_buf();
    let ffmpeg_name = ffmpeg_name.to_string();
    let ffprobe_name = ffprobe_name.to_string();

    tokio::task::spawn_blocking(move || {
        let file = std::fs::File::open(&archive_path)
            .map_err(|e| anyhow!("Failed to open archive: {}", e))?;

View on GitHub (pinned to 8600b91f42)