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
- Verify the parent: `mkdir -p "$FNM_DIR" && touch "$FNM_DIR/.probe" && rm "$FNM_DIR/.probe"` — any failure pinpoints the permission/space issue.
- Free space on the volume holding FNM_DIR (or move FNM_DIR to a larger disk).
- Remove stale partial staging entries under the fnm dir from earlier failed installs, then retry.
- 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
- Pre-create FNM_DIR during setup and verify write access with a probe file.
- Keep the FNM_DIR volume below ~90% usage before large installs.
- Clean partial staging leftovers after failed installs before retrying.
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
- Can't get a temporary file
- Can't create cd.cmd file for use-on-cd at {}: {}
- Failed to grab exit code
- Can't read user input
- Invalid OS string
AI-assisted analysis of Schniz/fnm@86adc9676c (2026-08-16).
Data as JSON: /api/errors/444013e032f7404b.
Report an issue: GitHub.