Schniz/fnm · error · anyhow::Error
Can't create cd.cmd file for use-on-cd at {}: {}
Error message
Can't create cd.cmd file for use-on-cd at {}: {} What it means
For `--use-on-cd`, the WindowsCmd shell writes an embedded `cd.cmd` helper into the fnm base directory (`config.base_dir_with_default().join("cd.cmd")`) using `File::create` + `write_all`. Any io failure is wrapped into this anyhow error (a returned Err, not a panic), naming the target path and the underlying cause.
Source
Thrown at src/shell/windows_cmd/mod.rs:33
std::env::var_os("path").ok_or_else(|| anyhow::anyhow!("Can't read PATH env var"))?;
let mut split_paths: Vec<_> = std::env::split_paths(¤t_path).collect();
split_paths.insert(0, path.to_path_buf());
let new_path = std::env::join_paths(split_paths)
.map_err(|err| anyhow::anyhow!("Can't join paths: {err}"))?;
let new_path = new_path
.to_str()
.ok_or_else(|| anyhow::anyhow!("Can't convert path to string"))?;
Ok(format!("SET PATH={new_path}"))
}
fn set_env_var(&self, name: &str, value: &str) -> String {
format!("SET {name}={value}")
}
fn use_on_cd(&self, config: &crate::config::FnmConfig) -> anyhow::Result<String> {
let path = config.base_dir_with_default().join("cd.cmd");
create_cd_file_at(&path).map_err(|source| {
anyhow::anyhow!(
"Can't create cd.cmd file for use-on-cd at {}: {}",
path.display(),
source
)
})?;
let path = path
.to_str()
.ok_or_else(|| anyhow::anyhow!("Can't read path to cd.cmd"))?;
Ok(format!("doskey cd=\"{path}\" $*"))
}
}
fn create_cd_file_at(path: &std::path::Path) -> std::io::Result<()> {
use std::io::Write;
let cmd_contents = include_bytes!("./cd.cmd");
let mut file = std::fs::File::create(path)?;
file.write_all(cmd_contents)?;
Ok(())View on GitHub (pinned to 86adc9676c)
Solutions
- Verify the base dir: `echo %FNM_DIR%` (or default location) then `icacls <dir>` / try `echo test > <dir>\cd.cmd` to reproduce the permission error.
- Create the directory if missing: `mkdir "%APPDATA%\fnm"`.
- Delete a stale/locked cd.cmd (close other cmd windows / let AV finish) and retry.
- Point FNM_DIR at a writable local path, or drop `--use-on-cd` and use PowerShell's use-on-cd instead.
Example fix
:: before set FNM_DIR=\\server\share\fnm fnm env --shell cmd --use-on-cd :: error: Can't create cd.cmd file ... (Access is denied) :: after set FNM_DIR=%LOCALAPPDATA%\fnm mkdir "%FNM_DIR%" fnm env --shell cmd --use-on-cd :: doskey cd="..." emitted
Defensive patterns
Strategy: validation
Validate before calling
// run before `fnm env --shell cmd --use-on-cd`
let base = std::env::var_os("FNM_DIR")
.map(std::path::PathBuf::from)
.unwrap_or_else(default_fnm_dir);
if !base.is_dir() { std::fs::create_dir_all(&base)?; }
let probe = base.join(".write-probe");
std::fs::write(&probe, b"")?; // PermissionDenied surfaces here, not inside fnm
std::fs::remove_file(&probe)?; Try / catch
match cmd_shell.use_on_cd(&config) {
Ok(macro_line) => println!("{macro_line}"),
Err(e) if e.chain().any(|c| c.downcast_ref::<std::io::Error>()
.is_some_and(|io| io.kind() == std::io::ErrorKind::PermissionDenied)) =>
eprintln!("base dir not writable: fix FNM_DIR permissions or delete locked cd.cmd"),
Err(e) => return Err(e),
} Prevention
- Pre-create the fnm base dir and verify write access during machine setup.
- Keep FNM_DIR on a local writable volume, not a locked network share.
- If AV locks cd.cmd, exclude the fnm dir or retry after the scan completes.
When it happens
Trigger: `fnm env --shell cmd --use-on-cd` when the fnm base dir (FNM_DIR if set, else the OS data dir such as %APPDATA%\fnm / ~/.local/share/fnm) is unwritable, missing, on a read-only volume, or when a locked/stale cd.cmd already exists there.
Common situations: Corporate machines with AppData redirection or write restrictions; FNM_DIR on a network share with deny-write ACLs; antivirus holding the freshly created cd.cmd; a directory named `cd.cmd` occupying the target path; full disk.
Related errors
- Can't read path to cd.cmd
- Can't read PATH env var
- Can't join paths: {err}
- Can't convert path to string
- Can't join paths: {source}
AI-assisted analysis of Schniz/fnm@86adc9676c (2026-08-16).
Data as JSON: /api/errors/614db4675b5712f9.
Report an issue: GitHub.