sigoden/dufs · error · anyhow::Error

Invalid auth

Error message

Invalid auth `{rule}`

What it means

Auth::new in src/args.rs (auth.rs) validates each --auth rule of the form user:pass@path. When an account segment contains a colon, it splits into user and pass; if either side is empty the rule is rejected with "Invalid auth `{rule}`". This catches rules like ':pass@/' or 'user:@/'.

Solutions

  1. Provide both a non-empty user and a non-empty password in each rule
  2. Quote the --auth value in the shell so special characters aren't stripped
  3. Use a hashed password (sha256) if embedding the plaintext is problematic
  4. Remember ':' separates user and pass — escape/restructure passwords that contain ':'

Example fix

# before
dufs --auth "admin:@/data"
# after
dufs --auth "admin:secretpw@/data"
Defensive patterns

Strategy: validation

Validate before calling

# every rule must be user:pass@path with non-empty user and pass
echo "$AUTH" | tr ',;' '\n' | while IFS= read -r r; do
  acct=${r%%@*}; user=${acct%%:*}; pass=${acct#*:}
  [ -n "$user" ] && [ -n "$pass" ] || { echo "bad auth rule: $r"; exit 1; }
done

Prevention

When it happens

Trigger: A rule like --auth "user:@/data" (empty password) or ":secret@/data" (empty user), where split_once(':') succeeds but one half is empty.

Common situations: Passwords containing special characters that a shell or config templater stripped; forgetting the password field; password legitimately empty but dufs requires non-empty both parts; colons in passwords splitting incorrectly — note ':' is the user/pass separator, so passwords containing ':' need care.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/auth.rs:70

    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();
        for (user, pass, paths) in account_paths_pairs.into_iter() {
            let mut access_paths = AccessPaths::default();
            access_paths
                .merge(paths)
                .ok_or_else(|| anyhow!("Invalid auth value `{user}:{pass}@{paths}"))?;

View on GitHub (pinned to fe7fd564f8)