spring-projects/spring-security · error · IllegalArgumentException

defaultPasswordEncoderForMatches cannot be null

Error message

defaultPasswordEncoderForMatches cannot be null

What it means

setDefaultPasswordEncoderForMatches chooses the PasswordEncoder used when an encoded password has no recognized id. Passing null removes that safety encoder and leaves matching without a fallback, so the setter rejects null with this IllegalArgumentException.

Solutions

  1. Pass a real PasswordEncoder instance, e.g. new UnmappedIdPasswordEncoder() style default or a BCryptPasswordEncoder, not null
  2. Check bean wiring/properties so the argument cannot be null (e.g. ensure the referenced bean exists)
  3. If you want the original throwing behavior, do not call the setter at all — the initial default already throws a descriptive IllegalArgumentException on unmapped ids

Example fix

// before
encoder.setDefaultPasswordEncoderForMatches(null);
// after
encoder.setDefaultPasswordEncoderForMatches(new BCryptPasswordEncoder());
Defensive patterns

Strategy: type-guard

Validate before calling

if (defaultEncoder == null) {
    throw new IllegalArgumentException("defaultPasswordEncoderForMatches must not be null");
}
encoder.setDefaultPasswordEncoderForMatches(defaultEncoder);

Type guard

if (!(candidate instanceof PasswordEncoder encoder)) {
    throw new IllegalStateException("Expected non-null PasswordEncoder, got: " + candidate);
}

Prevention

When it happens

Trigger: Calling delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(null), often via a Spring bean property or @Value injection that resolves to null.

Common situations: Bean wiring where a PasswordEncoder dependency failed to inject and arrives null; property placeholders that resolve to nothing; explicitly trying to 'unset' the default encoder (unsupported — pass a real encoder).

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/55037a6397441515. Report an issue: GitHub.

Appendix: source

Thrown at crypto/src/main/java/org/springframework/security/crypto/password/DelegatingPasswordEncoder.java:230

	}

	/**
	 * Sets the {@link PasswordEncoder} to delegate to for
	 * {@link #matches(CharSequence, String)} if the id is not mapped to a
	 * {@link PasswordEncoder}.
	 *
	 * <p>
	 * The encodedPassword provided will be the full password passed in including the
	 * {"id"} portion.* For example, if the password of "{notmapped}foobar" was used, the
	 * "id" would be "notmapped" and the encodedPassword passed into the
	 * {@link PasswordEncoder} would be "{notmapped}foobar".
	 * </p>
	 * @param defaultPasswordEncoderForMatches the encoder to use. The default is to throw
	 * an {@link IllegalArgumentException}
	 */
	public void setDefaultPasswordEncoderForMatches(PasswordEncoder defaultPasswordEncoderForMatches) {
		if (defaultPasswordEncoderForMatches == null) {
			throw new IllegalArgumentException("defaultPasswordEncoderForMatches cannot be null");
		}
		this.defaultPasswordEncoderForMatches = defaultPasswordEncoderForMatches;
	}

	@Override
	protected String encodeNonNullPassword(String rawPassword) {
		return this.idPrefix + this.idForEncode + this.idSuffix + this.passwordEncoderForEncode.encode(rawPassword);
	}

	@Override
	protected boolean matchesNonNull(String rawPassword, String prefixEncodedPassword) {
		String id = extractId(prefixEncodedPassword);
		PasswordEncoder delegate = this.idToPasswordEncoder.get(id);
		if (delegate == null) {
			return this.defaultPasswordEncoderForMatches.matches(rawPassword, prefixEncodedPassword);
		}
		String encodedPassword = extractEncodedPassword(prefixEncodedPassword);
		return delegate.matches(rawPassword, encodedPassword);

View on GitHub (pinned to 96852e8860)