Schniz/fnm · critical

Can't generate a temp directory

Error message

Can't generate a temp directory

What it means

`DirectoryPortal` stages a download into a `TempDir` created inside `parent_dir` and later atomically `fs::rename`s it onto the target. `new_in` calls `TempDir::new_in(parent_dir).expect("Can't generate a temp directory")`, which panics if the staging directory cannot be created — parent missing, not a directory, permission denied, or no space left on device.

Source

Thrown at src/directory_portal.rs:20

use std::path::Path;
use tempfile::TempDir;

/// A "work-in-progress" directory, which will "teleport" into the path
/// given in `target` only on successful, guarding from invalid state in the file system.
///
/// Underneath, it uses `fs::rename`, so make sure to make the `temp_dir` inside the same
/// mount as `target`. This is why we have the `new_in` constructor.
pub struct DirectoryPortal<P: AsRef<Path>> {
    temp_dir: TempDir,
    target: P,
}

impl<P: AsRef<Path>> DirectoryPortal<P> {
    /// Create a new portal which will keep the temp files in
    /// a subdirectory of `parent_dir` until teleporting to `target`.
    #[must_use]
    pub fn new_in(parent_dir: impl AsRef<Path>, target: P) -> Self {
        let temp_dir = TempDir::new_in(parent_dir).expect("Can't generate a temp directory");
        debug!("Created a temp directory in {}", temp_dir.path().display());
        Self { temp_dir, target }
    }

    pub fn teleport(self) -> std::io::Result<P> {
        debug!(
            "Moving directory {} into {}",
            self.temp_dir.path().display(),
            self.target.as_ref().display()
        );
        std::fs::rename(&self.temp_dir, &self.target)?;
        Ok(self.target)
    }
}

impl<P: AsRef<Path>> std::ops::Deref for DirectoryPortal<P> {
    type Target = Path;
    fn deref(&self) -> &Self::Target {

View on GitHub (pinned to 86adc9676c)

Solutions

  1. Verify the parent: `mkdir -p "$FNM_DIR" && touch "$FNM_DIR/.probe" && rm "$FNM_DIR/.probe"` — any failure pinpoints the permission/space issue.
  2. Free space on the volume holding FNM_DIR (or move FNM_DIR to a larger disk).
  3. Remove stale partial staging entries under the fnm dir from earlier failed installs, then retry.
  4. If patching fnm: propagate the io::Error (`TempDir::new_in(dir).map_err(...)?`) instead of expect.

Example fix

// before (src/directory_portal.rs)
let temp_dir = TempDir::new_in(parent_dir).expect("Can't generate a temp directory");

// after
let temp_dir = TempDir::new_in(parent_dir)
    .map_err(|e| anyhow::anyhow!("Can't generate a temp directory in {}: {e}", parent_dir.as_ref().display()))?;
Defensive patterns

Strategy: validation

Validate before calling

fn staging_dir_ready(base: &Path) -> std::io::Result<()> {
    std::fs::create_dir_all(base)?;
    let probe = tempfile::Builder::new().prefix("probe").tempdir_in(base)?;
    drop(probe); // create+remove succeeded => writable and has space
    Ok(())
}

Try / catch

std::panic::catch_unwind(|| directory_portal_new_in(parent, target))
    .unwrap_or_else(|_| {
        eprintln!("staging dir under {} unusable: check existence, permissions, disk space", parent.display());
    });

Prevention

When it happens

Trigger: Any install flow using the portal (`fnm install <version>`) when the parent dir — derived from FNM_DIR / the OS data dir — does not exist, is not writable, sits on a read-only or full volume, or a regular file occupies the path where the staging dir should be created.

Common situations: FNM_DIR pointing to a nonexistent or permission-locked path; AppData/local-share restrictions on managed machines; disk full mid-download-day; leftovers from a previous crashed install blocking the staging location; network mounts with odd create semantics.

Related errors


AI-assisted analysis of Schniz/fnm@86adc9676c (2026-08-16). Data as JSON: /api/errors/444013e032f7404b. Report an issue: GitHub.