{"record":{"id":"43c2f6397188eee5","repo":"spring-projects/spring-security","slug":"id-id-cannot-contain-idprefix","errorCode":null,"errorMessage":"id {id} cannot contain {idPrefix}","messagePattern":"id (.+?) cannot contain (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"crypto/src/main/java/org/springframework/security/crypto/password/DelegatingPasswordEncoder.java","lineNumber":201,"sourceCode":"\t\t\tthrow new IllegalArgumentException(\"prefix cannot be null\");\n\t\t}\n\t\tif (idSuffix == null || idSuffix.isEmpty()) {\n\t\t\tthrow new IllegalArgumentException(\"suffix cannot be empty\");\n\t\t}\n\t\tif (idPrefix.contains(idSuffix)) {\n\t\t\tthrow new IllegalArgumentException(\"idPrefix \" + idPrefix + \" cannot contain idSuffix \" + idSuffix);\n\t\t}\n\n\t\tif (!idToPasswordEncoder.containsKey(idForEncode)) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"idForEncode \" + idForEncode + \"is not found in idToPasswordEncoder \" + idToPasswordEncoder);\n\t\t}\n\t\tfor (String id : idToPasswordEncoder.keySet()) {\n\t\t\tif (id == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!idPrefix.isEmpty() && id.contains(idPrefix)) {\n\t\t\t\tthrow new IllegalArgumentException(\"id \" + id + \" cannot contain \" + idPrefix);\n\t\t\t}\n\t\t\tif (id.contains(idSuffix)) {\n\t\t\t\tthrow new IllegalArgumentException(\"id \" + id + \" cannot contain \" + idSuffix);\n\t\t\t}\n\t\t}\n\t\tthis.idForEncode = idForEncode;\n\t\tthis.passwordEncoderForEncode = idToPasswordEncoder.get(idForEncode);\n\t\tthis.idToPasswordEncoder = new HashMap<>(idToPasswordEncoder);\n\t\tthis.idPrefix = idPrefix;\n\t\tthis.idSuffix = idSuffix;\n\t}\n\n\t/**\n\t * Sets the {@link PasswordEncoder} to delegate to for\n\t * {@link #matches(CharSequence, String)} if the id is not mapped to a\n\t * {@link PasswordEncoder}.\n\t *\n\t * <p>","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/password/DelegatingPasswordEncoder.java#L183-L219","documentation":"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.","triggerScenarios":"Registering an encoder in idToPasswordEncoder whose key contains the idPrefix (e.g. key \"my{encoder\" while idPrefix is \"{\").","commonSituations":"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.","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)"],"exampleFix":"// before\nencoders.put(\"{bcrypt}\", new BCryptPasswordEncoder());\n// after\nencoders.put(\"bcrypt\", new BCryptPasswordEncoder());","handlingStrategy":"validation","validationCode":"for (String id : encoders.keySet()) {\n    if (id != null && id.contains(\"{\")) {\n        throw new IllegalStateException(\"Encoder id must not contain '{': \" + id);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    return new DelegatingPasswordEncoder(idForEncode, encoders, \"{\", \"}\");\n} catch (IllegalArgumentException e) {\n    log.error(\"Encoder id conflicts with prefix/suffix: {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Never use '{...}' wrapped strings as encoder ids","If ids come from config/user input, strip '{' and '}' characters first"],"tags":["spring-security","illegal-argument","password-encoding","identifier-validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}