Morganamilo/paru · error · anyhow::Error
failed to find state directory
Error message
failed to find state directory
What it means
Config::new() resolves a state directory with dirs::state_dir(), falling back to dirs::cache_dir(). If neither can be determined, it fails with this error. The state dir holds runtime data like devel.toml.
Solutions
- Set HOME to a writable directory before running paru.
- Set XDG_STATE_HOME (e.g. $HOME/.local/state) or XDG_CACHE_HOME so one resolver succeeds.
- Verify the runtime user has a valid home directory in the user database.
- As a last resort in containers, create /home/user, set HOME, and run as that user.
Example fix
# before (systemd service) [Service] ExecStart=/usr/bin/paru -Syu # after [Service] Environment=HOME=/home/build Environment=XDG_STATE_HOME=/home/build/.local/state ExecStart=/usr/bin/paru -Syu
Defensive patterns
Strategy: validation
Validate before calling
if dirs::state_dir().is_none() && dirs::cache_dir().is_none() {
eprintln!("set XDG_STATE_HOME or XDG_CACHE_HOME (and HOME) before running");
std::process::exit(1);
} Type guard
fn has_state_dir() -> bool { dirs::state_dir().or_else(dirs::cache_dir).is_some() } Prevention
- Set XDG_STATE_HOME in systemd units via Environment=.
- Ensure the runtime user has a valid home directory.
- Run containers as a non-root user with a defined HOME.
When it happens
Trigger: Calling Config::new() when both dirs::state_dir() (XDG_STATE_HOME + home resolution) and dirs::cache_dir() (XDG_CACHE_HOME + home) return None, i.e. no resolvable user home.
Common situations: Running paru under systemd timers/services with a minimal environment; containers or chroots without HOME; XDG_STATE_HOME and XDG_CACHE_HOME both unset AND HOME unset/unreadable.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- failed to find config directory
- failed to find cache directory
- config file ' ' does not exist
- invalid value ' ' for key ' ', expected
- unknown mode
AI-assisted analysis of Morganamilo/paru@9ac3578807 (2026-09-12).
Data as JSON: /api/errors/b143577c96a0ed23.
Report an issue: GitHub.
Appendix: source
Thrown at src/config.rs:588
CallbackKind::Directive(_, key, value) => self.parse_directive(key, value),
};
let filename = cb.filename.unwrap_or("paru.conf");
err.map_err(|e| anyhow!("{}:{}: {}", filename, cb.line_number, e))
}
}
impl Config {
pub fn new() -> Result<Self> {
let cache =
dirs::cache_dir().ok_or_else(|| anyhow!(tr!("failed to find cache directory")))?;
let cache = cache.join("paru");
let config =
dirs::config_dir().ok_or_else(|| anyhow!(tr!("failed to find config directory")))?;
let config = config.join("paru");
let state = dirs::state_dir()
.or_else(dirs::cache_dir)
.ok_or_else(|| anyhow!(tr!("failed to find state directory")))?;
let state = state.join("paru");
let build_dir = cache.join("clone");
let old_old_devel_path = cache.join("devel.json");
let old_devel_path = state.join("devel.json");
let devel_path = state.join("devel.toml");
let config_path = config.join("paru.conf");
let old = if old_devel_path.exists() {
Some(&old_devel_path)
} else if old_old_devel_path.exists() {
Some(&old_old_devel_path)
} else {
None
};
let cache_dir = cache;
let state_dir = state;View on GitHub (pinned to 9ac3578807)