spring-projects/spring-security · error · IllegalArgumentException
id {id} cannot contain {idPrefix}
Error message
id {id} cannot contain {idPrefix} What it means
Each encoder id in the map becomes part of the stored password string ({id}...). If an id itself contains the idPrefix, the stored encoding would be ambiguous and unparseable, so the constructor rejects it with this IllegalArgumentException.
Source
Thrown at crypto/src/main/java/org/springframework/security/crypto/password/DelegatingPasswordEncoder.java:201
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);
}
if (id.contains(idSuffix)) {
throw new IllegalArgumentException("id " + id + " cannot contain " + idSuffix);
}
}
this.idForEncode = idForEncode;
this.passwordEncoderForEncode = idToPasswordEncoder.get(idForEncode);
this.idToPasswordEncoder = new HashMap<>(idToPasswordEncoder);
this.idPrefix = idPrefix;
this.idSuffix = idSuffix;
}
/**
* Sets the {@link PasswordEncoder} to delegate to for
* {@link #matches(CharSequence, String)} if the id is not mapped to a
* {@link PasswordEncoder}.
*
* <p>View on GitHub (pinned to 96852e8860)
Solutions
- Use bare encoder ids that contain only characters outside the prefix/suffix (letters, digits, hyphen)
- Strip any '{' or '}' from map keys before registering encoders
- If you have a stored '{bcrypt}' style string, unwrap it: key = value.substring(1, value.length()-1)
Example fix
// before
encoders.put("{bcrypt}", new BCryptPasswordEncoder());
// after
encoders.put("bcrypt", new BCryptPasswordEncoder()); Defensive patterns
Strategy: validation
Validate before calling
for (String id : encoders.keySet()) {
if (id != null && id.contains("{")) {
throw new IllegalStateException("Encoder id must not contain '{': " + id);
}
} Try / catch
try {
return new DelegatingPasswordEncoder(idForEncode, encoders, "{", "}");
} catch (IllegalArgumentException e) {
log.error("Encoder id conflicts with prefix/suffix: {}", e.getMessage());
throw e;
} Prevention
- Never use '{...}' wrapped strings as encoder ids
- If ids come from config/user input, strip '{' and '}' characters first
When it happens
Trigger: Registering an encoder in idToPasswordEncoder whose key contains the idPrefix (e.g. key "my{encoder" while idPrefix is "{").
Common situations: Composing encoder ids dynamically from user or config input that accidentally embeds '{'; building id strings like prefix + name; copy-paste of full '{id}' strings used as map keys instead of the bare id.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- id {id} cannot contain {idSuffix}
- suffix cannot be empty
- idPrefix {idPrefix} cannot contain idSuffix {idSuffix}
- idForEncode {idForEncode}is not found in idToPasswordEncoder
- Unsupported implementation of Sid
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/43c2f6397188eee5.
Report an issue: GitHub.