Morganamilo/paru · error

{}:{}: {}

Error message

{}:{}: {}

What it means

This is a wrapper error: when parsing a config file (paru.conf or an Include-ed file) fails, paru attaches the filename and line number of the offending directive/callback to the underlying parse error via anyhow! and map_err. It tells the developer exactly which file and line caused the config parse failure. The original error message is preserved as the source of the anyhow chain.

Solutions

  1. Read the error's filename:line part and fix the offending line in that file
  2. Check the option name and value against paru's supported directives (paru.conf man page / PARU_CONF docs)
  3. Restore a known-good paru.conf (e.g. /usr/share/doc/paru/paru.conf example)
  4. Use paru --paruconf <path> to test an alternate config file in isolation

Example fix

// before (paru.conf)
BottomUp = maybe

// after (paru.conf)
BottomUp = true
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate each non-empty, non-comment line of paru.conf has form key = value
let bad: Vec<&str> = conf.lines().filter(|l| !l.trim().is_empty() && !l.trim().starts_with('#') && !l.contains('=') && !l.trim().starts_with('[') && !l.starts_with("Include")).collect();
if !bad.is_empty() { eprintln!("malformed lines: {:?}", bad); }

Try / catch

match Config::new() {
    Ok(c) => c,
    Err(e) => { eprintln!("paru config error: {:?}", e); std::process::exit(1); }
}

Prevention

When it happens

Trigger: Any parse_directive / parse call inside config file parsing that returns Err; the error is mapped at src/config.rs:574 into '{filename}:{line_number}: {e}'. Triggered by any malformed key=value line or unknown directive in paru.conf or an included config file.

Common situations: Typo in a paru.conf option name (e.g. 'BottomUp' vs 'bottomup'), invalid value for an enum-like option, malformed Include file lines, or editing paru.conf by hand and breaking syntax.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Morganamilo/paru@9ac3578807 (2026-09-12). Data as JSON: /api/errors/b74a3d8f262961b9. Report an issue: GitHub.

Appendix: source

Thrown at src/config.rs:574

        let err = match cb.kind {
            CallbackKind::Section(section) => {
                self.section = Some(section.to_string());
                if !matches!(section, "options" | "bin" | "env")
                    && self.pkgbuild_repos.repo(section).is_none()
                {
                    if matches!(section, "local" | "aur" | "pkg" | "base") || section.contains('.')
                    {
                        bail!(tr!("section can not be called {}", section));
                    }
                    self.pkgbuild_repos.add_repo(section.to_string());
                }
                Ok(())
            }
            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");

View on GitHub (pinned to 9ac3578807)