{"record":{"id":"eacd05248cb73ce7","repo":"espanso/espanso","slug":"unable-to-create-config-directory","errorCode":null,"errorMessage":"unable to create config directory","messagePattern":"unable to create config directory","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"espanso/src/path/mod.rs","lineNumber":75,"sourceCode":"    pub packages: PathBuf,\n\n    pub is_portable_mode: bool,\n}\n\npub fn resolve_paths(\n    force_config_dir: Option<&Path>,\n    force_package_dir: Option<&Path>,\n    force_runtime_dir: Option<&Path>,\n) -> Paths {\n    let config_dir = if let Some(config_dir) = force_config_dir {\n        config_dir.to_path_buf()\n    } else if let Some(config_dir) = get_config_dir() {\n        config_dir\n    } else {\n        // Create the config directory if not already present\n        let config_dir = get_default_config_path();\n        info!(\"creating config directory in {}\", config_dir.display());\n        create_dir_all(&config_dir).expect(\"unable to create config directory\");\n        config_dir\n    };\n\n    let runtime_dir = if let Some(runtime_dir) = force_runtime_dir {\n        runtime_dir.to_path_buf()\n    } else if let Some(runtime_dir) = get_runtime_dir() {\n        runtime_dir\n    } else {\n        // Create the runtime directory if not already present\n        let runtime_dir = if is_portable_mode() {\n            get_portable_runtime_path().expect(\"unable to obtain runtime directory path\")\n        } else {\n            get_default_runtime_path()\n        };\n        info!(\"creating runtime directory in {}\", runtime_dir.display());\n        create_dir_all(&runtime_dir).expect(\"unable to create runtime directory\");\n        runtime_dir\n    };","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/espanso/espanso/blob/e6c3736675048026a057f1c4803d59242482fa7b/espanso/src/path/mod.rs#L57-L93","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// shell instead of code\n// before\n$ espanso start\nthread 'main' panicked: unable to create config directory\n// after\n$ ls -la ~/.config/espanso   # found a plain file\n$ mv ~/.config/espanso ~/.config/espanso.bak\n$ espanso start  # now creates the directory successfully","handlingStrategy":"validation","validationCode":"let config_dir = dirs::config_dir().map(|d| d.join(\"espanso\"));\nif let Some(dir) = &config_dir {\n    if let Ok(md) = std::fs::metadata(dir) {\n        if !md.is_dir() { eprintln!(\"{} exists but is not a directory\", dir.display()); }\n    } else if let Some(parent) = dir.parent() {\n        let writable = std::fs::metadata(parent).map(|m| !m.permissions().readonly()).unwrap_or(false);\n        if !writable { eprintln!(\"parent {} not writable\", parent.display()); }\n    }\n}","typeGuard":"fn is_creatable_dir(path: &std::path::Path) -> bool {\n    !path.exists() || path.is_dir()\n}","tryCatchPattern":"match std::fs::create_dir_all(&config_dir) {\n    Ok(()) => {},\n    Err(e) => { eprintln!(\"config dir {}: {}\", config_dir.display(), e); std::process::exit(1); }\n}","preventionTips":["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)"],"tags":["filesystem","mkdir","panic","configuration"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"e6c3736675048026a057f1c4803d59242482fa7b","analyzedAt":"2026-09-06T15:16:34.240Z","contentChangedAt":"2026-09-06T15:16:34.240Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}