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

  1. Add the missing id to the encoder map used to build DelegatingPasswordEncoder (e.g. encoders.put("noop", PasswordEncoderFactories.createDelegatingPasswordEncoder() style NoOpPasswordEncoder))
  2. Call setDefaultPasswordEncoderForMatches(encoder) to give unknown ids a fallback
  3. Inspect the actual stored passwords' id prefixes and register every distinct one
  4. 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

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


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)