herdrdev/herdr · error · io::Error
failed to create private herdr ssh config directory
Error message
failed to create private herdr ssh config directory
What it means
Windows implementation of create_remote_ssh_config_dir mirrors the fallback logic: it tries candidate private directories, skips ones that already exist, and if every candidate fails for a real reason (permissions, read-only disk) it returns this AlreadyExists error as a terminal 'no usable directory' marker rather than the underlying IO error.
Source
Thrown at src/platform/windows.rs:135
system_config: std::env::var_os("PROGRAMDATA")
.map(PathBuf::from)
.map(|dir| dir.join("ssh").join("ssh_config")),
multiplexing: false,
}
}
pub(crate) fn create_remote_ssh_config_dir(_control_socket_name: &str) -> std::io::Result<PathBuf> {
let base = remote_private_temp_base();
std::fs::create_dir_all(&base)?;
for attempt in 0..100 {
let dir = base.join(format!("ssh-{}-{attempt}", std::process::id()));
match create_remote_private_dir(&dir) {
Ok(()) => return Ok(dir),
Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => continue,
Err(err) => return Err(err),
}
}
Err(std::io::Error::new(
std::io::ErrorKind::AlreadyExists,
"failed to create private herdr ssh config directory",
))
}
pub(crate) fn create_remote_ssh_config_file(
path: &std::path::Path,
) -> std::io::Result<std::fs::File> {
std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(path)
}
pub(crate) fn create_remote_private_dir(path: &std::path::Path) -> std::io::Result<()> {
use interprocess::os::windows::security_descriptor::{
AsSecurityDescriptorExt as _, SecurityDescriptor,
};View on GitHub (pinned to f457cff4f2)
Solutions
- Check ACLs on %USERPROFILE% and any herdr data directories; grant the process create-directory rights
- Ensure %USERPROFILE% (or the configured home) is on a writable volume
- Pre-create the expected herdr ssh config directory manually so creation is unnecessary
- If AV/group policy is blocking, add an exclusion for the Herdr data directory
Defensive patterns
Strategy: fallback
Validate before calling
let base = std::env::var_os("USERPROFILE").map(std::path::PathBuf::from);
if let Some(base) = base {
let meta = std::fs::metadata(&base);
if meta.is_err() || meta?.permissions().readonly() {
// surface unwritable-profile problem before calling
}
} Try / catch
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists && e.to_string().contains("private herdr ssh config") => {
// no usable dir: offer fallback to %TEMP%-based dir or prompt for elevation
} Prevention
- Verify the user profile directory is writable during install
- Pre-create the herdr ssh config directory on first run
- Add AV exclusions for the Herdr data directory in managed environments
When it happens
Trigger: Calling create_remote_ssh_config_dir on Windows when create_remote_private_dir fails on every candidate directory with a non-AlreadyExists error — e.g. ACCESS_DENIED on the parent folder, read-only volume, or antivirus blocking directory creation.
Common situations: UserProfile redirected to a locked-down or roaming profile directory; corporate policy or AV intercepting creation of dot-directories; running Herdr from a service account whose profile path is unwritable.
Related errors
- failed to create private herdr ssh config directory
- failed to create private herdr ssh config directory
- failed to {operation} managed plugin checkout at {}; close a
- failed to create unique scrollback temp file
- direct terminal attach is not supported on Windows yet
AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28).
Data as JSON: /api/errors/bb253f5cb0d8fb8a.
Report an issue: GitHub.