denoland/deno · error · anyhow::Error

Failed to move extracted package into {}: {e} (initial: {ren

Error message

Failed to move extracted package into {}: {e} (initial: {rename_err})

What it means

extract_tarball_gz_atomic stages the extraction into a sibling temp dir and then renames it into place. If that final rename fails, the code cleans up the staging dir and re-checks whether another concurrent process already published dest (is_materialized_package); only if not does it throw this error containing both the rename failure and the initial error, indicating the package could not be atomically installed at dest.

Source

Thrown at cli/tools/installer/npm_compat.rs:1120

        // Another process published a complete copy first. Its tree is as good
        // as ours, so keep it and drop the staging dir.
        let _ = std::fs::remove_dir_all(&tmp_dir);
        return Ok(());
      }
      // `dest` is stale: half-extracted by a killed process, or written
      // non-atomically by an older Deno. Clearing it is what heals a cache that
      // is already poisoned - otherwise every later run skips the download and
      // keeps type checking against an incomplete tree.
      let _ = std::fs::remove_dir_all(dest);
      match std::fs::rename(&tmp_dir, dest) {
        Ok(()) => Ok(()),
        Err(e) => {
          let _ = std::fs::remove_dir_all(&tmp_dir);
          // A third process may have published `dest` in between.
          if is_materialized_package(dest) {
            return Ok(());
          }
          Err(anyhow!(
            "Failed to move extracted package into {}: {e} (initial: {rename_err})",
            dest.display()
          ))
        }
      }
    }
  }
}

/// Extract a gzipped npm-style tarball into `dest`, stripping the leading
/// `package/` directory the way `tar --strip-components=1` does. Replaces
/// the previous `tar` shell-out so the install works the same on Linux,
/// macOS (BSD tar), Windows, and minimal containers without `tar`/`curl`.
fn extract_tarball_gz(gz_bytes: &[u8], dest: &Path) -> Result<(), AnyError> {
  std::fs::create_dir_all(dest)?;
  let mut archive = tar::Archive::new(GzDecoder::new(gz_bytes));
  for entry in archive.entries()? {
    let mut entry = entry?;

View on GitHub (pinned to 336da420f4)

Solutions

  1. Re-run the install command — the failure is often transient (lock held by another process or AV scan).
  2. Clear the corrupted target directory in the npm cache (remove dest) and retry so extraction starts fresh.
  3. Check permissions and free space on the cache parent directory.
  4. Reduce concurrency (avoid running multiple deno installs against the same DENO_DIR simultaneously) or exclude the cache dir from antivirus scanning.
Defensive patterns

Strategy: retry

Try / catch

// Rust
match extract_tarball_gz_atomic(&gz, &dest) {
  Ok(()) => {},
  Err(e) if e.to_string().contains("Failed to move extracted package") => {
    std::thread::sleep(std::time::Duration::from_millis(250));
    std::fs::remove_dir_all(&dest).ok(); // clear partial/conflicting target, then retry
    extract_tarball_gz_atomic(&gz, &dest)?;
  }
  Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The std::fs::rename of the staging dir into dest fails (dest locked/AV-scanned on Windows, cross-device rename despite sibling staging, permission denied, dest recreated in a conflicting state by a racing process between the rename attempt and the recheck).

Common situations: Parallel deno installs racing on the same npm cache entry; antivirus/indexer holding the target dir open on Windows; read-only or full cache filesystem; permission changes on the cache directory.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of denoland/deno@336da420f4 (2026-09-11). Data as JSON: /api/errors/6b3664f2939b52ba. Report an issue: GitHub.