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
On fallback platforms, Herdr creates a private directory (~/.ssh-like, mode 700) for remote SSH control sockets and config. When every candidate private directory fails to create for a non-AlreadyExists reason and all paths are exhausted, this AlreadyExists error is returned as a terminal marker meaning 'no usable private directory could be established'.
Source
Thrown at src/platform/fallback.rs:35
super::RemoteSshConfigPaths {
user_config: std::env::var_os("HOME")
.map(PathBuf::from)
.map(|home| home.join(".ssh").join("config")),
system_config: None,
multiplexing: false,
}
}
pub(crate) fn create_remote_ssh_config_dir(_control_socket_name: &str) -> std::io::Result<PathBuf> {
for attempt in 0..100 {
let dir = std::env::temp_dir().join(format!("herdr-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> {
let mut options = std::fs::OpenOptions::new();
options.write(true).create_new(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
options.mode(0o600);
}
options.open(path)
}
View on GitHub (pinned to f457cff4f2)
Solutions
- Check permissions on your home and SSH config directories; ensure the process can create mode-700 directories
- Ensure HOME is set to a writable directory for the Herdr process
- Pre-create the expected private herdr ssh directory with mode 700 so creation succeeds immediately
- If running in a sandbox/container, mount or redirect HOME to writable storage
Example fix
// before: $HOME is read-only, creation fails // after: pre-create with correct perms mkdir -p ~/.local/share/herdr/ssh && chmod 700 ~/.local/share/herdr/ssh
Defensive patterns
Strategy: fallback
Validate before calling
let dir = std::env::home_dir().unwrap_or_default().join(".ssh");
if !dir.is_dir() && std::fs::create_dir_all(&dir).is_err() {
// surface a permissions problem before calling create_remote_ssh_config_dir
} Try / catch
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists && e.to_string().contains("private herdr ssh config") => {
// treat as 'no usable private dir': prompt user or use a temp dir fallback
} Prevention
- Ensure HOME is set and writable for the Herdr process
- Pre-create the private directory with mode 700 during install
- Log the underlying create_remote_private_dir errors, since the terminal marker hides them
When it happens
Trigger: Calling create_remote_ssh_config_dir on a fallback platform when all candidate directories fail creation (permission denied on the parent, read-only home) or none of the attempted creations succeed. The AlreadyExists kind is a sentinel: candidates whose directory already exists are skipped, and reaching the end without success yields this error.
Common situations: Home directory permissions lock down creation of the private dir; HOME unset or pointing somewhere unwritable; sandboxed/containerized runs with a read-only home; tests that exhaust candidate paths deliberately.
Related errors
- failed to create private herdr ssh config directory
- failed to create private herdr ssh config directory
- failed to create unique scrollback temp file
- failed to {operation} managed plugin checkout at {}; close a
- login shell {shell:?} is not executable
AI-assisted analysis of herdrdev/herdr@f457cff4f2 (2026-08-28).
Data as JSON: /api/errors/2cbe315e75b7b6b9.
Report an issue: GitHub.