sigoden/dufs · error · anyhow::Error
invalid nonce
Error message
invalid nonce
What it means
HTTP Digest auth nonces must be exactly 34 bytes: 8 hex chars encoding a Unix-seconds timestamp followed by 26 hex chars of digest. `validate_nonce` rejects any nonce with the wrong length as 'invalid nonce' before further parsing.
Solutions
- Use the nonce exactly as issued by this server in its WWW-Authenticate challenge.
- Check the client's Digest implementation generates/passes the full nonce string.
- Inspect the raw Authorization header for truncation or whitespace mangling.
- Fall back to Basic auth if the client cannot do Digest correctly.
Example fix
// before Authorization: Digest username="u", nonce="abc123" (too short) // after Authorization: Digest username="u", nonce="<34-char nonce from server challenge>"
Defensive patterns
Strategy: validation
Validate before calling
fn nonce_wellformed(n: &str) -> bool { n.len() == 34 && n.chars().all(|c| c.is_ascii_hexdigit()) }
if !nonce_wellformed(nonce) { request_new_challenge(); } Prevention
- Echo the server's nonce verbatim, no trimming/altering
- Use a maintained Digest auth library instead of hand-rolling
- Log the raw Authorization header when debugging
- Never reuse nonces from a different server
When it happens
Trigger: A client sends a WWW-Authenticate Digest response whose nonce is not 34 bytes long — e.g. empty, server-generated nonce from a different implementation, or truncated.
Common situations: Custom HTTP clients hand-building Digest headers; replaying nonces from another server; corrupted or cut-off Authorization headers.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of sigoden/dufs@fe7fd564f8 (2026-09-09).
Data as JSON: /api/errors/f25ec4fc069274d9.
Report an issue: GitHub.
Appendix: source
Thrown at src/auth.rs:527
}
None
} else {
None
}
}
fn derive_secret_key(user: &str, pass: &str) -> SigningKey {
let mut hasher = Sha256::new();
hasher.update(format!("{user}:{pass}").as_bytes());
let hash = hasher.finalize();
SigningKey::from_bytes(&hash.into())
}
/// Check if a nonce is still valid.
/// Return an error if it was never valid
fn validate_nonce(nonce: &[u8]) -> Result<bool> {
if nonce.len() != 34 {
bail!("invalid nonce");
}
//parse hex
if let Ok(n) = std::str::from_utf8(nonce) {
//get time
if let Ok(secs_nonce) = u32::from_str_radix(&n[..8], 16) {
//check time
let now = unix_now();
let secs_now = now.as_secs() as u32;
if let Some(dur) = secs_now.checked_sub(secs_nonce) {
//check hash
let mut h = NONCESTARTHASH.clone();
h.consume(secs_nonce.to_be_bytes());
let h = format!("{:x}", h.finalize());
if h[..26] == n[8..34] {
return Ok(dur < DIGEST_AUTH_TIMEOUT);
}
}View on GitHub (pinned to fe7fd564f8)