spring-projects/spring-security · error · IllegalArgumentException

Encoded password does not look like SCrypt: {encodedPassword

Error message

Encoded password does not look like SCrypt: {encodedPassword}

What it means

Before deciding whether an existing hash should be re-hashed with stronger parameters, upgradeEncodingNonNull splits the stored SCrypt string on '$' and expects exactly 4 parts. A stored value that is not in scrypt's `$s0$params$salt$key` format cannot be parsed, so an IllegalArgumentException naming the offending encoded password is thrown.

Source

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

		return new SCryptPasswordEncoder(DEFAULT_CPU_COST, DEFAULT_MEMORY_COST, DEFAULT_PARALLELISM, DEFAULT_KEY_LENGTH,
				DEFAULT_SALT_LENGTH);
	}

	@Override
	protected String encodeNonNullPassword(String rawPassword) {
		return digest(rawPassword, this.saltGenerator.generateKey());
	}

	@Override
	protected boolean matchesNonNull(String rawPassword, String encodedPassword) {
		return decodeAndCheckMatches(rawPassword, encodedPassword);
	}

	@Override
	protected boolean upgradeEncodingNonNull(String encodedPassword) {
		String[] parts = encodedPassword.split("\\$");
		if (parts.length != 4) {
			throw new IllegalArgumentException("Encoded password does not look like SCrypt: " + encodedPassword);
		}
		long params = Long.parseLong(parts[1], 16);
		int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff);
		int memoryCost = (int) params >> 8 & 0xff;
		int parallelization = (int) params & 0xff;
		return cpuCost < this.cpuCost || memoryCost < this.memoryCost || parallelization < this.parallelization;
	}

	private boolean decodeAndCheckMatches(CharSequence rawPassword, String encodedPassword) {
		String[] parts = encodedPassword.split("\\$");
		if (parts.length != 4) {
			return false;
		}
		long params = Long.parseLong(parts[1], 16);
		byte[] salt = decodePart(parts[2]);
		byte[] derived = decodePart(parts[3]);
		int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff);
		int memoryCost = (int) params >> 8 & 0xff;

View on GitHub (pinned to 96852e8860)

Solutions

  1. Only call upgradeEncoding for hashes known to be scrypt-encoded; check the prefix (e.g. startsWith("$e0801$")) or keep the encoder type per user.
  2. Wrap the upgradeEncoding call in try-catch for IllegalArgumentException and treat foreign formats as needing a full re-encode on next login.
  3. Fix/restore corrupted hash rows in the data store.

Example fix

// before
boolean upgrade = encoder.upgradeEncoding(storedPassword);
// after
boolean upgrade = storedPassword.startsWith("$e0801$") && encoder.upgradeEncoding(storedPassword);
Defensive patterns

Strategy: type-guard

Validate before calling

boolean isScrypt = storedPassword != null && storedPassword.chars().filter(c -> c == '$').count() == 4
        && storedPassword.startsWith("$");

Type guard

boolean looksLikeScrypt(String encoded) {
    return encoded != null && encoded.startsWith("$s")
        && encoded.split("\\$").length == 4;
}

Try / catch

boolean upgrade;
try {
    upgrade = encoder.upgradeEncoding(encoded);
} catch (IllegalArgumentException e) {
    upgrade = true; // not scrypt: force re-encode on next login
}

Prevention

When it happens

Trigger: Calling `upgradeEncoding(encodedPassword)` (inherited flow invoking upgradeEncodingNonNull) with a hash that was not produced by SCryptPasswordEncoder — e.g. a bcrypt hash, a plain password, or a truncated/corrupted scrypt string.

Common situations: User table migrated from another PasswordEncoder (bcrypt/argon2) without prefix detection; hand-edited or truncated hash rows; column truncation losing part of the hash in the database.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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