{"record":{"id":"ea0fda79dd143293","repo":"Morganamilo/paru","slug":"failed-to-find-config-directory","errorCode":null,"errorMessage":"failed to find config directory","messagePattern":"failed to find config directory","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/config.rs","lineNumber":584,"sourceCode":"                    self.pkgbuild_repos.add_repo(section.to_string());\n                }\n                Ok(())\n            }\n            CallbackKind::Directive(_, key, value) => self.parse_directive(key, value),\n        };\n\n        let filename = cb.filename.unwrap_or(\"paru.conf\");\n        err.map_err(|e| anyhow!(\"{}:{}: {}\", filename, cb.line_number, e))\n    }\n}\n\nimpl Config {\n    pub fn new() -> Result<Self> {\n        let cache =\n            dirs::cache_dir().ok_or_else(|| anyhow!(tr!(\"failed to find cache directory\")))?;\n        let cache = cache.join(\"paru\");\n        let config =\n            dirs::config_dir().ok_or_else(|| anyhow!(tr!(\"failed to find config directory\")))?;\n        let config = config.join(\"paru\");\n        let state = dirs::state_dir()\n            .or_else(dirs::cache_dir)\n            .ok_or_else(|| anyhow!(tr!(\"failed to find state directory\")))?;\n        let state = state.join(\"paru\");\n\n        let build_dir = cache.join(\"clone\");\n        let old_old_devel_path = cache.join(\"devel.json\");\n        let old_devel_path = state.join(\"devel.json\");\n        let devel_path = state.join(\"devel.toml\");\n        let config_path = config.join(\"paru.conf\");\n\n        let old = if old_devel_path.exists() {\n            Some(&old_devel_path)\n        } else if old_old_devel_path.exists() {\n            Some(&old_old_devel_path)\n        } else {\n            None","sourceCodeStart":566,"sourceCodeEnd":602,"githubUrl":"https://github.com/Morganamilo/paru/blob/9ac3578807a87858651e81a02586ceb947686e7c/src/config.rs#L566-L602","documentation":"paru's Config::new() resolves the user's XDG config directory via the `dirs` crate (dirs::config_dir()) and appends \"paru\" to it. If no config directory can be determined (e.g. $XDG_CONFIG_HOME unset and no home directory resolvable), it returns this anyhow error instead of constructing a Config.","triggerScenarios":"Calling Config::new() (directly or via paru startup) when dirs::config_dir() returns None — typically because HOME is unset, the passwd entry lacks a home dir, or running in a stripped environment (cron, systemd service, containers).","commonSituations":"Running paru from a systemd unit, CI job, or Docker container without HOME/XDG_CONFIG_HOME set; running as a user with a malformed /etc/passwd entry; musl/minimal chroot environments.","solutions":["Set HOME to the user's home directory before invoking paru.","Set XDG_CONFIG_HOME explicitly (e.g. XDG_CONFIG_HOME=$HOME/.config).","Check that the invoking user exists in /etc/passwd with a valid home directory.","If embedding paru as a library, ensure dirs::config_dir() prerequisites are met before calling Config::new()."],"exampleFix":"// before (container CMD)\nCMD [\"paru\", \"-Syu\"]\n// after\nCMD [\"sh\", \"-c\", \"export HOME=${HOME:-/root} XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config} && exec paru -Syu\"]","handlingStrategy":"validation","validationCode":"if std::env::var(\"HOME\").is_err() && std::env::var(\"XDG_CONFIG_HOME\").is_err() {\n    std::env::set_var(\"XDG_CONFIG_HOME\", \"/root/.config\"); // or fail fast with a clear message\n}\nassert!(dirs::config_dir().is_some(), \"no config dir resolvable\");","typeGuard":"fn has_config_dir() -> bool { dirs::config_dir().is_some() }","tryCatchPattern":null,"preventionTips":["Always export HOME in service units, cron jobs, and containers.","Set XDG_CONFIG_HOME explicitly in minimal environments.","Smoke-test CLI tools under `env -i` to catch missing env dependencies early."],"tags":["config","environment","xdg"],"backgroundTag":"missing-env-var","analyzedSha":"9ac3578807a87858651e81a02586ceb947686e7c","analyzedAt":"2026-09-12T04:57:59.861Z","contentChangedAt":"2026-09-12T04:57:59.861Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}