spring-projects/spring-security · error · IllegalArgumentException
Unsupported password prefix '{prefix}'
Error message
Unsupported password prefix '{prefix}' What it means
During matches(), getSalt examines the prefix extracted from the encoded password and throws this IllegalArgumentException when the prefix is neither {SHA}, {SSHA} nor their lowercase variants. It means the stored password was not produced by LdapShaPasswordEncoder (or was corrupted), so salt extraction — and therefore comparison — cannot proceed.
Source
Thrown at crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java:162
*/
@Override
protected boolean matchesNonNull(String rawPassword, String encodedPassword) {
String prefix = extractPrefix(encodedPassword);
if (prefix == null) {
return PasswordEncoderUtils.equals(encodedPassword, rawPassword);
}
byte[] salt = getSalt(encodedPassword, prefix);
int startOfHash = prefix.length();
String encodedRawPass = encode(rawPassword, salt).substring(startOfHash);
return PasswordEncoderUtils.equals(encodedRawPass, encodedPassword.substring(startOfHash));
}
private byte @Nullable [] getSalt(String encodedPassword, String prefix) {
if (prefix.equals(SSHA_PREFIX) || prefix.equals(SSHA_PREFIX_LC)) {
return extractSalt(encodedPassword);
}
if (!prefix.equals(SHA_PREFIX) && !prefix.equals(SHA_PREFIX_LC)) {
throw new IllegalArgumentException("Unsupported password prefix '" + prefix + "'");
}
// Standard SHA
return null;
}
/**
* Returns the hash prefix or null if there isn't one.
*/
private @Nullable String extractPrefix(String encPass) {
if (!encPass.startsWith("{")) {
return null;
}
int secondBrace = encPass.lastIndexOf('}');
if (secondBrace < 0) {
throw new IllegalArgumentException("Couldn't find closing brace for SHA prefix");
}
return encPass.substring(0, secondBrace + 1);
}View on GitHub (pinned to 96852e8860)
Solutions
- Only feed this encoder hashes it produced: strings starting with {SHA} or {SSHA} (or lowercase forms).
- Re-encode the user's password with LdapShaPasswordEncoder and update the stored value.
- Use DelegatingPasswordEncoder to route each stored hash to the encoder matching its prefix instead of hard-wiring LdapShaPasswordEncoder.
Example fix
// before
boolean ok = ldapEncoder.matches(raw, stored); // stored = "{bcrypt}$2a$..."
// after
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
boolean ok = encoder.matches(raw, stored); Defensive patterns
Strategy: validation
Validate before calling
if (!(stored.startsWith("{SHA}") || stored.startsWith("{SSHA}")
|| stored.startsWith("{sha}") || stored.startsWith("{ssha}"))) {
throw new IllegalArgumentException("not an LDAP SHA/SSHA hash: " + prefixOf(stored));
}
boolean ok = ldapEncoder.matches(raw, stored); Try / catch
try {
ok = ldapEncoder.matches(raw, stored);
} catch (IllegalArgumentException e) {
// unsupported prefix: route to the appropriate encoder or flag the record
} Prevention
- Use DelegatingPasswordEncoder so {id}-prefixed hashes reach the right encoder automatically.
- Never manually edit stored hashes; regenerate them with the intended encoder.
When it happens
Trigger: Calling matches(rawPassword, encodedPassword) where encodedPassword has a different or unrecognized brace prefix such as {bcrypt}, {CRYPT}, or no prefix format the encoder understands.
Common situations: A password store migrated between encoders (e.g. from bcrypt to LDAP SHA or vice versa) with stale entries; manually edited seed data with a typo in the prefix; DelegatingPasswordEncoder-style {id} hashes passed to this encoder directly.
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
- Invalid encoded Argon2-hash
- Invalid algorithm type: X
- Amount of performance parameters invalid
- Invalid memory parameter
- Invalid iterations parameter
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/ad727b44283d48fa.
Report an issue: GitHub.