shadowsocks/shadowsocks-rust · error
`users[].password` length must be exactly the same as method
Error message
`users[].password` length must be exactly the same as method's key length
What it means
Raised during server config validation when a user's key (derived from `users[].password`) does not have exactly the same byte length as the server method's key length. AEAD-2022 multi-user mode requires every user key to be exactly the cipher's key size; shadowsocks-service rejects the config otherwise.
Source
Thrown at crates/shadowsocks-service/src/config.rs:2985
// Users' key must match key length
if let Some(user_manager) = server.user_manager() {
#[cfg(feature = "aead-cipher-2022")]
if server.method().is_aead_2022() {
use shadowsocks::config::method_support_eih;
if user_manager.user_count() > 0 && !method_support_eih(server.method()) {
let err = Error::new(
ErrorKind::Invalid,
"server method doesn't support Extended Identity Header (EIH), remove `users`",
Some(format!("method {}", server.method())),
);
return Err(err);
}
}
let key_len = server.method().key_len();
for user in user_manager.users_iter() {
if user.key().len() != key_len {
let err = Error::new(
ErrorKind::Malformed,
"`users[].password` length must be exactly the same as method's key length",
None,
);
return Err(err);
}
}
}
}
Ok(())
}
}
impl fmt::Display for Config {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Convert to json
View on GitHub (pinned to 8eb0f0a65b)
Solutions
- Regenerate each user's password as a base64-encoded random key of exactly method.key_len() bytes (16 for aes-128-gcm, 32 for aes-256-gcm / chacha20-poly1305)
- Or switch the method to a variant matching the key length you already have (e.g. 2022-blake3-aes-128-gcm for 16-byte keys)
- Validate all user key lengths with the server method before deploying the config
Example fix
// before
{"method":"2022-blake3-aes-256-gcm","users":[{"password":"dGVzdA=="}]} // 4-byte key
// after
{"method":"2022-blake3-aes-256-gcm","users":[{"password":"<base64 of 32 random bytes>"}]} Defensive patterns
Strategy: validation
Validate before calling
let key_len = server.method().key_len();
for user in &server.users {
assert_eq!(user.key().len(), key_len, "user key must be {} bytes", key_len);
} Type guard
fn user_key_valid(user: &ServerUser, method: &ServerConfigMethod) -> bool {
user.key().len() == method.key_len()
} Try / catch
match config.validate() {
Err(e) if e.to_string().contains("key length") => eprintln!("regenerate user keys to exactly {} bytes", method.key_len()),
Err(e) => return Err(e),
Ok(v) => v,
} Prevention
- Generate keys with a helper sized to the method: rand 16 or 32 bytes then base64
- Re-validate all user keys whenever the method changes
- Store keys with their intended method in deployment tooling
When it happens
Trigger: Loading a config where any entry in `servers[].users` has a password whose decoded key length differs from server.method().key_len() (e.g. a 16-byte key under 2022-blake3-aes-256-gcm which needs 32 bytes).
Common situations: Generating user keys with the wrong size for the cipher; swapping the method between 128- and 256-bit AEAD-2022 variants without regenerating user keys; typos or truncation in base64 keys.
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
- `protocol` invalid
- invalid `mode`
- `server`, `server_port`, `method`, `password` must be provid
- missing `locals` for client configuration
- balancer.max_server_rtt must be > 0
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/805f1031b1fe5ceb.
Report an issue: GitHub.