spring-projects/spring-security · error · IllegalArgumentException

prefix cannot be null

Error message

prefix cannot be null

What it means

DelegatingPasswordEncoder's full constructor requires a non-null idPrefix (default "{") and throws IllegalArgumentException('prefix cannot be null') when it is null. The prefix/suffix delimit the encoder id inside encoded password strings and are needed to parse {id}... on matches().

Source

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

	}

	/**
	 * Creates a new instance.
	 * @param idForEncode the id used to lookup which {@link PasswordEncoder} should be
	 * used for {@link #encode(CharSequence)}
	 * @param idToPasswordEncoder a Map of id to {@link PasswordEncoder} used to determine
	 * which {@link PasswordEncoder} should be used for
	 * @param idPrefix the prefix that denotes the start of the id in the encoded results
	 * @param idSuffix the suffix that denotes the end of an id in the encoded results
	 * {@link #matches(CharSequence, String)}
	 */
	public DelegatingPasswordEncoder(String idForEncode, Map<String, PasswordEncoder> idToPasswordEncoder,
			String idPrefix, String idSuffix) {
		if (idForEncode == null) {
			throw new IllegalArgumentException("idForEncode cannot be null");
		}
		if (idPrefix == null) {
			throw new IllegalArgumentException("prefix cannot be null");
		}
		if (idSuffix == null || idSuffix.isEmpty()) {
			throw new IllegalArgumentException("suffix cannot be empty");
		}
		if (idPrefix.contains(idSuffix)) {
			throw new IllegalArgumentException("idPrefix " + idPrefix + " cannot contain idSuffix " + idSuffix);
		}

		if (!idToPasswordEncoder.containsKey(idForEncode)) {
			throw new IllegalArgumentException(
					"idForEncode " + idForEncode + "is not found in idToPasswordEncoder " + idToPasswordEncoder);
		}
		for (String id : idToPasswordEncoder.keySet()) {
			if (id == null) {
				continue;
			}
			if (!idPrefix.isEmpty() && id.contains(idPrefix)) {
				throw new IllegalArgumentException("id " + id + " cannot contain " + idPrefix);

View on GitHub (pinned to 96852e8860)

Solutions

  1. Pass non-null delimiters, typically "{" and "}".
  2. To use no delimiters, pass empty strings where allowed, but note the suffix must be non-null and non-empty and the prefix must not contain the suffix.
  3. Validate configured delimiter values before constructing the encoder.

Example fix

// before
String prefix = props.get("pw.prefix"); // null
PasswordEncoder encoder = new DelegatingPasswordEncoder("bcrypt", encoders, prefix, "}");
// after
String prefix = props.getOrDefault("pw.prefix", "{");
PasswordEncoder encoder = new DelegatingPasswordEncoder("bcrypt", encoders, prefix, "}");
Defensive patterns

Strategy: validation

Validate before calling

if (idPrefix == null) {
    throw new IllegalArgumentException("idPrefix must be non-null (default \"{\")");
}
if (idSuffix == null || idSuffix.isEmpty()) {
    throw new IllegalArgumentException("idSuffix must be non-empty (default \"}\")");
}
PasswordEncoder encoder = new DelegatingPasswordEncoder(idForEncode, idToPasswordEncoder, idPrefix, idSuffix);

Type guard

boolean areValidDelimiters(String prefix, String suffix) {
    return prefix != null && suffix != null && !suffix.isEmpty() && !prefix.contains(suffix);
}

Try / catch

try {
    encoder = new DelegatingPasswordEncoder(idForEncode, idToPasswordEncoder, idPrefix, idSuffix);
} catch (IllegalArgumentException ex) {
    encoder = new DelegatingPasswordEncoder(idForEncode, idToPasswordEncoder, "{", "}");
}

Prevention

When it happens

Trigger: Calling new DelegatingPasswordEncoder(idForEncode, idToPasswordEncoder, null, "}") or passing a prefix variable that resolved to null; customizing delimiters and forgetting the prefix while setting the suffix.

Common situations: Externalizing prefix/suffix to properties where the prefix key is absent; intentionally wanting no prefix by passing null instead of an empty-safe value; copy-paste of the suffix argument into the prefix slot.

Related errors


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