sigoden/dufs · error · anyhow::Error

Invalid auth, no duplicate anonymous rules

Error message

Invalid auth, no duplicate anonymous rules

What it means

Auth::new in src/auth.rs parses the comma/semicolon-separated --auth rule list. An empty account (rule with no user:pass before '@') registers anonymous access; registering anonymous access twice would make the ACL ambiguous, so it bails with 'Invalid auth, no duplicate anonymous rules'.

Solutions

  1. Keep at most one rule without a user:pass (anonymous) in --auth
  2. Give every additional rule an explicit account, e.g. user:pass@/:rw
  3. Merge anonymous paths into the single anonymous rule or split into multiple dufs instances
  4. Reorder so anonymous rule appears once and protected rules use accounts

Example fix

# before
dufs --auth "@/:rw,@/public:r"
# after
dufs --auth "@/:r,admin:pass@/:rw"
Defensive patterns

Strategy: validation

Validate before calling

# ensure at most one anonymous (no user:pass) rule
ANON_COUNT=$(echo "$AUTH" | tr ',' '\n' | grep -cv '@.*@\|^[^@]*:.*@')
# count rules lacking user:pass before '@':
anon=$(echo "$AUTH" | tr ',;' '\n' | grep -c '^@'); [ "$anon" -le 1 ] || { echo "duplicate anonymous rules"; exit 1; }

Prevention

When it happens

Trigger: Passing two anonymous rules in --auth, e.g. --auth "@/:rw,@/public:r" — the second rule with an empty account triggers the bail because annoy_paths is already Some.

Common situations: Trying to grant different permissions to anonymous users on different paths; generated auth strings that accidentally contain an empty account segment; misunderstanding that anonymous access is all-or-nothing in dufs.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of sigoden/dufs@fe7fd564f8 (2026-09-09). Data as JSON: /api/errors/3a79f432327127d9. Report an issue: GitHub.

Appendix: source

Thrown at src/auth.rs:65

        }
    }
}

impl AccessControl {
    pub fn new(raw_rules: &[&str]) -> Result<Self> {
        if raw_rules.is_empty() {
            return Ok(Self::default());
        }
        let new_raw_rules = split_rules(raw_rules);
        let mut use_hashed_password = false;
        let mut annoy_paths = None;
        let mut account_paths_pairs = vec![];
        for rule in &new_raw_rules {
            let (account, paths) =
                split_account_paths(rule).ok_or_else(|| anyhow!("Invalid auth `{rule}`"))?;
            if account.is_empty() {
                if annoy_paths.is_some() {
                    bail!("Invalid auth, no duplicate anonymous rules");
                }
                annoy_paths = Some(paths)
            } else if let Some((user, pass)) = account.split_once(':') {
                if user.is_empty() || pass.is_empty() {
                    bail!("Invalid auth `{rule}`");
                }
                account_paths_pairs.push((user, pass, paths));
            }
        }
        let mut anonymous = None;
        if let Some(paths) = annoy_paths {
            let mut access_paths = AccessPaths::default();
            access_paths
                .merge(paths)
                .ok_or_else(|| anyhow!("Invalid auth value `@{paths}"))?;
            anonymous = Some(access_paths);
        }
        let mut users = IndexMap::new();

View on GitHub (pinned to fe7fd564f8)