spring-projects/spring-security · error · IllegalArgumentException

Key length must be >= 1 and <= {Integer.MAX_VALUE}

Error message

Key length must be >= 1 and <= {Integer.MAX_VALUE}

What it means

The derived-key length must be a positive int within range; since values above Integer.MAX_VALUE cannot even be expressed as an int, the check effectively rejects keyLength < 1. SCryptPasswordEncoder throws IllegalArgumentException so no encoder is created with a nonsense key length.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/scrypt/SCryptPasswordEncoder.java:113

	 * default is currently 16.
	 */
	public SCryptPasswordEncoder(int cpuCost, int memoryCost, int parallelization, int keyLength, int saltLength) {
		if (cpuCost <= 1) {
			throw new IllegalArgumentException("Cpu cost parameter must be > 1.");
		}
		if (memoryCost == 1 && cpuCost > 65536) {
			throw new IllegalArgumentException("Cpu cost parameter must be > 1 and < 65536.");
		}
		if (memoryCost < 1) {
			throw new IllegalArgumentException("Memory cost must be >= 1.");
		}
		int maxParallel = Integer.MAX_VALUE / (128 * memoryCost * 8);
		if (parallelization < 1 || parallelization > maxParallel) {
			throw new IllegalArgumentException("Parallelisation parameter p must be >= 1 and <= " + maxParallel
					+ " (based on block size r of " + memoryCost + ")");
		}
		if (keyLength < 1 || keyLength > Integer.MAX_VALUE) {
			throw new IllegalArgumentException("Key length must be >= 1 and <= " + Integer.MAX_VALUE);
		}
		if (saltLength < 1 || saltLength > Integer.MAX_VALUE) {
			throw new IllegalArgumentException("Salt length must be >= 1 and <= " + Integer.MAX_VALUE);
		}
		this.cpuCost = cpuCost;
		this.memoryCost = memoryCost;
		this.parallelization = parallelization;
		this.keyLength = keyLength;
		this.saltGenerator = KeyGenerators.secureRandom(saltLength);
	}

	/**
	 * Constructs a SCrypt password encoder with cpu cost of 16,384, memory cost of 8,
	 * parallelization of 1, a key length of 32 and a salt length of 64 bytes.
	 * @return the {@link SCryptPasswordEncoder}
	 * @since 5.8
	 * @deprecated Use {@link #defaultsForSpringSecurity_v5_8()} instead
	 */

View on GitHub (pinned to 96852e8860)

Solutions

  1. Pass a positive keyLength in bytes (e.g. 32 for 256-bit keys).
  2. Validate the configured value is >= 1 before constructing.
  3. Use the no-arg constructor for defaults (keyLength 32).

Example fix

// before
new SCryptPasswordEncoder(16384, 8, 1, 0, 64);
// after
new SCryptPasswordEncoder(16384, 8, 1, 32, 64);
Defensive patterns

Strategy: validation

Validate before calling

if (keyLength < 1 || keyLength > Integer.MAX_VALUE) {
    throw new IllegalArgumentException("keyLength must be >= 1: " + keyLength);
}
new SCryptPasswordEncoder(cpuCost, memoryCost, p, keyLength, saltLen);

Try / catch

try {
    encoder = new SCryptPasswordEncoder(cpuCost, r, p, keyLength, saltLen);
} catch (IllegalArgumentException e) {
    encoder = new SCryptPasswordEncoder(); // defaults: keyLength 32
}

Prevention

When it happens

Trigger: `new SCryptPasswordEncoder(cpuCost, memoryCost, parallelization, keyLength, saltLength)` with keyLength < 1 (values > Integer.MAX_VALUE are impossible for an int parameter).

Common situations: keyLength read from config defaulting to 0 or -1; using 0 meaning 'default' when the API requires an explicit positive length; accidentally passing byte-vs-bit confusion like 0.

Related errors


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