spring-projects/spring-security · error · IllegalArgumentException
saltGenerator cannot be null
Error message
saltGenerator cannot be null
What it means
The LdapShaPasswordEncoder(BytesKeyGenerator) constructor rejects a null saltGenerator with this IllegalArgumentException. The encoder needs a generator to produce random salt bytes for {SSHA} hashes (and salt comparison during matching), so a null generator would break both encode and matches. The no-arg constructor supplies KeyGenerators.secureRandom() automatically.
Source
Thrown at crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java:72
private static final String SSHA_PREFIX = "{SSHA}";
private static final String SSHA_PREFIX_LC = SSHA_PREFIX.toLowerCase(Locale.ENGLISH);
private static final String SHA_PREFIX = "{SHA}";
private static final String SHA_PREFIX_LC = SHA_PREFIX.toLowerCase(Locale.ENGLISH);
private BytesKeyGenerator saltGenerator;
private boolean forceLowerCasePrefix;
public LdapShaPasswordEncoder() {
this(KeyGenerators.secureRandom());
}
public LdapShaPasswordEncoder(BytesKeyGenerator saltGenerator) {
if (saltGenerator == null) {
throw new IllegalArgumentException("saltGenerator cannot be null");
}
this.saltGenerator = saltGenerator;
}
private byte[] combineHashAndSalt(byte[] hash, byte @Nullable [] salt) {
if (salt == null) {
return hash;
}
byte[] hashAndSalt = new byte[hash.length + salt.length];
System.arraycopy(hash, 0, hashAndSalt, 0, hash.length);
System.arraycopy(salt, 0, hashAndSalt, hash.length, salt.length);
return hashAndSalt;
}
/**
* Calculates the hash of password (and salt bytes, if supplied) and returns a base64
* encoded concatenation of the hash and salt, prefixed with {SHA} (or {SSHA} if salt
* was used).View on GitHub (pinned to 96852e8860)
Solutions
- Pass a real generator: new LdapShaPasswordEncoder(KeyGenerators.secureRandom()).
- Use the no-argument constructor LdapShaPasswordEncoder() which defaults to a secure random generator.
- Ensure any dependency-injected BytesKeyGenerator bean is actually defined and not null at construction time.
Example fix
// before
encoder = new LdapShaPasswordEncoder(saltGenerator); // null when bean missing
// after
encoder = new LdapShaPasswordEncoder(
saltGenerator != null ? saltGenerator : KeyGenerators.secureRandom()); Defensive patterns
Strategy: type-guard
Type guard
BytesKeyGenerator safeGen = (gen != null) ? gen : KeyGenerators.secureRandom(); LdapShaPasswordEncoder encoder = new LdapShaPasswordEncoder(safeGen);
Try / catch
try {
encoder = new LdapShaPasswordEncoder(saltGenerator);
} catch (IllegalArgumentException e) {
encoder = new LdapShaPasswordEncoder(); // secureRandom default
} Prevention
- Prefer the no-arg constructor unless you need a deterministic/custom generator (e.g. tests).
- Ensure the BytesKeyGenerator bean exists before injection; use @Autowired(required=true) semantics or constructor validation.
When it happens
Trigger: Directly invoking new LdapShaPasswordEncoder(null), e.g. passing a field or injected dependency that failed to initialize.
Common situations: Spring wiring where a salt generator bean is absent so the constructor argument resolves to null; code paths that conditionally build the encoder and skip generator creation.
Related errors
- Unsupported password prefix '{prefix}'
- Couldn't find closing brace for SHA prefix
- secretKeyFactoryAlgorithm cannot be null
- managerPassword is required if managerDn is supplied
- No BaseLdapPathContextSource instances found. Have you added
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/1415cc1d92a25efc.
Report an issue: GitHub.