spring-projects/spring-security · error · IllegalArgumentException

salt cannot be null

Error message

salt cannot be null

What it means

BCrypt.hashpw() throws "salt cannot be null" when the salt parameter (the modular salt string like $2a$10$...) is null. A null salt string cannot be parsed to extract the cost and raw salt needed for hashing.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java:619

	 */
	public static String hashpw(byte passwordb[], String salt) {
		return hashpw(passwordb, salt, false);
	}

	private static String hashpw(byte passwordb[], String salt, boolean for_check) {
		BCrypt B;
		String real_salt;
		byte saltb[], hashed[];
		char minor = (char) 0;
		int rounds, off;
		StringBuilder rs = new StringBuilder();

		// Enforce max length for new passwords only
		if (!for_check && passwordb.length > 72) {
			throw new IllegalArgumentException("password cannot be more than 72 bytes");
		}
		if (salt == null) {
			throw new IllegalArgumentException("salt cannot be null");
		}

		int saltLength = salt.length();

		if (saltLength < 28) {
			throw new IllegalArgumentException("Invalid salt");
		}

		if (salt.charAt(0) != '$' || salt.charAt(1) != '2') {
			throw new IllegalArgumentException("Invalid salt version");
		}
		if (salt.charAt(2) == '$') {
			off = 3;
		}
		else {
			minor = salt.charAt(2);
			if ((minor != 'a' && minor != 'x' && minor != 'y' && minor != 'b') || salt.charAt(3) != '$') {
				throw new IllegalArgumentException("Invalid salt revision");

View on GitHub (pinned to 96852e8860)

Solutions

  1. Generate a salt with BCrypt.gensalt() when none exists instead of passing null
  2. Null-check the salt before calling hashpw
  3. When verifying, always pass the full stored hash string as the salt parameter

Example fix

// before
String hash = BCrypt.hashpw(pw, storedSalt); // storedSalt may be null
// after
String salt = (storedSalt != null) ? storedSalt : BCrypt.gensalt();
String hash = BCrypt.hashpw(pw, salt);
Defensive patterns

Strategy: type-guard

Validate before calling

if (salt == null || salt.isEmpty()) {
    salt = BCrypt.gensalt();
}

Type guard

boolean hasSalt(String salt) { return salt != null && !salt.isEmpty(); }

Try / catch

try {
    hash = BCrypt.hashpw(pw, salt);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("salt cannot be null")) { hash = BCrypt.hashpw(pw, BCrypt.gensalt()); }
}

Prevention

When it happens

Trigger: Passing null as the second argument of BCrypt.hashpw, or a password-encoder configured with a null salt value (Spring Security's BCryptPasswordEncoder internally handles salt, so this appears with direct BCrypt API use).

Common situations: Storing/reading the per-user salt in a database column that is null, or a helper method returning null salt on cache miss.

Related errors


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