spring-projects/spring-security · error · IllegalArgumentException
There is no password encoder mapped for the id
Error message
There is no password encoder mapped for the id '%s'. Check your configuration to ensure it matches one of the registered encoders.
What it means
During matches(), the '{id}' prefix extracted from the stored password was non-blank but not registered in the encoder map. Since no default matcher resolves it, the library throws this IllegalArgumentException telling you to align configuration with the stored ids.
Solutions
- Add the missing id to the encoder map used to build DelegatingPasswordEncoder (e.g. encoders.put("noop", PasswordEncoderFactories.createDelegatingPasswordEncoder() style NoOpPasswordEncoder))
- Call setDefaultPasswordEncoderForMatches(encoder) to give unknown ids a fallback
- Inspect the actual stored passwords' id prefixes and register every distinct one
- Normalize stored ids to lowercase to avoid case mismatches
Example fix
// before
Map<String, PasswordEncoder> encoders = Map.of("bcrypt", new BCryptPasswordEncoder());
// stored password is '{noop}secret'
// after
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
PasswordEncoder encoder = new DelegatingPasswordEncoder("bcrypt", encoders, "{", "}");
Defensive patterns
Strategy: validation
Validate before calling
String id = encodedPassword.contains("{") && encodedPassword.contains("}")
? encodedPassword.substring(1, encodedPassword.indexOf('}')) : null;
if (id != null && !registeredIds.contains(id)) {
log.warn("Stored password uses unregistered encoder id: {}", id);
} Try / catch
try {
return encoder.matches(rawPassword, storedPassword);
} catch (IllegalArgumentException e) {
log.error("Unmapped encoder id in stored password: {}", e.getMessage());
return false;
} Prevention
- Register every encoder id present in your password store (including 'noop') in the map
- Scan the credentials column on startup for distinct {id} prefixes and assert they are all registered
- Call setDefaultPasswordEncoderForMatches to absorb unknown ids
- Compare ids case-insensitively when migrating data
When it happens
Trigger: matches(rawPassword, encodedPassword) called with a stored password like '{argon2}...' or '{noop}...' when the DelegatingPasswordEncoder was built without an 'argon2'/'noop' entry in idToPasswordEncoder and without setDefaultPasswordEncoderForMatches.
Common situations: Passwords encoded by a different application/version with more encoder types; Spring Security upgrade where PasswordEncoderFactories default ids changed; config map missing the 'noop' id so plaintext-stored passwords fail; id case mismatch ('Bcrypt' vs 'bcrypt').
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- A filter chain that matches any request
- Can not set rememberMeCookieName and custom…
- Cannot apply to already built object
- Cannot configure both a CorsConfigurationSource and a…
- client_registration_not_found
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/9dcee6cc50a75249.
Report an issue: GitHub.
Appendix: source
Thrown at crypto/src/main/java/org/springframework/security/crypto/password/DelegatingPasswordEncoder.java:298
return prefixEncodedPassword.substring(start + this.idSuffix.length());
}
/**
* Default {@link PasswordEncoder} that throws an exception telling that a suitable
* {@link PasswordEncoder} for the id could not be found.
*/
private class UnmappedIdPasswordEncoder extends AbstractValidatingPasswordEncoder {
@Override
protected String encodeNonNullPassword(String rawPassword) {
throw new UnsupportedOperationException("encode is not supported");
}
@Override
protected boolean matchesNonNull(String rawPassword, String prefixEncodedPassword) {
String id = extractId(prefixEncodedPassword);
if (id != null && !id.isBlank()) {
throw new IllegalArgumentException(String.format(NO_PASSWORD_ENCODER_MAPPED, id));
}
if (prefixEncodedPassword != null && !prefixEncodedPassword.isBlank()) {
int start = prefixEncodedPassword.indexOf(DelegatingPasswordEncoder.this.idPrefix);
int end = prefixEncodedPassword.indexOf(DelegatingPasswordEncoder.this.idSuffix, start);
if (start < 0 && end < 0) {
throw new IllegalArgumentException(NO_PASSWORD_ENCODER_PREFIX);
}
}
throw new IllegalArgumentException(String.format(MALFORMED_PASSWORD_ENCODER_PREFIX,
DelegatingPasswordEncoder.this.idPrefix, DelegatingPasswordEncoder.this.idSuffix));
}
}
}
View on GitHub (pinned to 96852e8860)