espanso/espanso · critical
unable to create config directory
Error message
unable to create config directory
What it means
espanso's resolve_paths panics with 'unable to create config directory' when it cannot create the default config directory (e.g. ~/.config/espanso on Linux, ~/Library/Application Support/espanso on macOS, %APPDATA%\espanso on Windows). This is reached only when no existing config directory was detected anywhere (portable, $HOME/.espanso, $HOME/.config/espanso, legacy macOS, default) and create_dir_all fails. It aborts the whole process because espanso cannot run without a config directory.
Source
Thrown at espanso/src/path/mod.rs:75
pub packages: PathBuf,
pub is_portable_mode: bool,
}
pub fn resolve_paths(
force_config_dir: Option<&Path>,
force_package_dir: Option<&Path>,
force_runtime_dir: Option<&Path>,
) -> Paths {
let config_dir = if let Some(config_dir) = force_config_dir {
config_dir.to_path_buf()
} else if let Some(config_dir) = get_config_dir() {
config_dir
} else {
// Create the config directory if not already present
let config_dir = get_default_config_path();
info!("creating config directory in {}", config_dir.display());
create_dir_all(&config_dir).expect("unable to create config directory");
config_dir
};
let runtime_dir = if let Some(runtime_dir) = force_runtime_dir {
runtime_dir.to_path_buf()
} else if let Some(runtime_dir) = get_runtime_dir() {
runtime_dir
} else {
// Create the runtime directory if not already present
let runtime_dir = if is_portable_mode() {
get_portable_runtime_path().expect("unable to obtain runtime directory path")
} else {
get_default_runtime_path()
};
info!("creating runtime directory in {}", runtime_dir.display());
create_dir_all(&runtime_dir).expect("unable to create runtime directory");
runtime_dir
};View on GitHub (pinned to e6c3736675)
Solutions
- Check whether the target path (dirs::config_dir()/espanso) exists as a file and remove/rename it so it can be a directory.
- Fix permissions on the parent directory (chown/chmod) so create_dir_all can succeed; ensure $HOME points to a writable directory.
- Pass --config-dir to force espanso to use an existing writable directory instead of the default location.
- Free disk space or remount the filesystem read-write if the create failed due to ENOSPC/EROFS.
Example fix
// shell instead of code // before $ espanso start thread 'main' panicked: unable to create config directory // after $ ls -la ~/.config/espanso # found a plain file $ mv ~/.config/espanso ~/.config/espanso.bak $ espanso start # now creates the directory successfully
Defensive patterns
Strategy: validation
Validate before calling
let config_dir = dirs::config_dir().map(|d| d.join("espanso"));
if let Some(dir) = &config_dir {
if let Ok(md) = std::fs::metadata(dir) {
if !md.is_dir() { eprintln!("{} exists but is not a directory", dir.display()); }
} else if let Some(parent) = dir.parent() {
let writable = std::fs::metadata(parent).map(|m| !m.permissions().readonly()).unwrap_or(false);
if !writable { eprintln!("parent {} not writable", parent.display()); }
}
} Type guard
fn is_creatable_dir(path: &std::path::Path) -> bool {
!path.exists() || path.is_dir()
} Try / catch
match std::fs::create_dir_all(&config_dir) {
Ok(()) => {},
Err(e) => { eprintln!("config dir {}: {}", config_dir.display(), e); std::process::exit(1); }
} Prevention
- Verify the default config path is not occupied by a regular file before first launch
- Ensure $HOME/XDG_CONFIG_HOME point to writable, absolute paths
- Run espanso as the same user that owns the config location; avoid sudo
- Pass --config-dir explicitly in managed deployments (systemd, CI, containers)
When it happens
Trigger: Calling resolve_paths (or any espanso CLI entrypoint that calls it) when: the parent of the default config path exists but is not writable (permission denied), the path exists as a regular FILE instead of a directory, the disk is full or read-only, or an intermediate directory (e.g. $HOME/.config) is unwritable.
Common situations: Running espanso as a different user than the one owning the config path (e.g. under systemd/sudo with a wrong $HOME), HOME unset or mispointed so the default path lands somewhere unwritable, a stale file named like the config dir left by a botched migration, restoring backups that changed ownership, running from a read-only root filesystem or full disk.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- unable to create runtime directory
- unable to create packages directory
- unable to create reference to lock file: {}
- unable to unlock lock_file: {:?}
- unable to write preference for key {key}
AI-assisted analysis of espanso/espanso@e6c3736675 (2026-09-06).
Data as JSON: /api/errors/eacd05248cb73ce7.
Report an issue: GitHub.