spring-projects/spring-security · error · IllegalArgumentException

Invalid algorithm type: X

Error message

Invalid algorithm type: X

What it means

After splitting the encoded hash, decode() dispatches on the algorithm segment (parts[1]); only argon2d, argon2i, and argon2id are supported. Any other identifier — or an empty/garbled one — causes this IllegalArgumentException. The hash's algorithm token must match the PHC Argon2 spec.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/argon2/Argon2EncodingUtils.java:114

	 * output. Both are required. The binary salt length and the output length must be in
	 * the allowed ranges defined in argon2.h.
	 * @param encodedHash the Argon2 hash string as described above
	 * @return an {@link Argon2Hash} object containing the raw hash and the
	 * {@link Argon2Parameters}.
	 * @throws IllegalArgumentException if the encoded hash is malformed
	 */
	static Argon2Hash decode(String encodedHash) throws IllegalArgumentException {
		Argon2Parameters.Builder paramsBuilder;
		String[] parts = encodedHash.split("\\$");
		if (parts.length < 4) {
			throw new IllegalArgumentException("Invalid encoded Argon2-hash");
		}
		int currentPart = 1;
		paramsBuilder = switch (parts[currentPart++]) {
			case "argon2d" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_d);
			case "argon2i" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_i);
			case "argon2id" -> new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id);
			default -> throw new IllegalArgumentException("Invalid algorithm type: " + parts[1]);
		};
		if (parts[currentPart].startsWith("v=")) {
			paramsBuilder.withVersion(Integer.parseInt(parts[currentPart].substring(2)));
			currentPart++;
		}
		String[] performanceParams = parts[currentPart++].split(",");
		if (performanceParams.length != 3) {
			throw new IllegalArgumentException("Amount of performance parameters invalid");
		}
		if (!performanceParams[0].startsWith("m=")) {
			throw new IllegalArgumentException("Invalid memory parameter");
		}
		paramsBuilder.withMemoryAsKB(Integer.parseInt(performanceParams[0].substring(2)));
		if (!performanceParams[1].startsWith("t=")) {
			throw new IllegalArgumentException("Invalid iterations parameter");
		}
		paramsBuilder.withIterations(Integer.parseInt(performanceParams[1].substring(2)));
		if (!performanceParams[2].startsWith("p=")) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Ensure the hash was produced by an Argon2 variant and its algorithm token is lowercase 'argon2id'/'argon2i'/'argon2d'
  2. Use the correct decoder/encoder for the actual algorithm (e.g. BCryptPasswordEncoder for '$2a$' hashes)
  3. During migrations, version-prefix stored hashes and dispatch to the right PasswordEncoder via DelegatingPasswordEncoder

Example fix

// before
PasswordEncoder encoder = new Argon2PasswordEncoder(); // used on legacy bcrypt hashes
// after
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); // routes by {id} prefix
Defensive patterns

Strategy: validation

Validate before calling

static boolean isArgon2Algorithm(String encodedHash) {
    return encodedHash != null && encodedHash.startsWith("$argon2id$") || encodedHash.startsWith("$argon2i$") || encodedHash.startsWith("$argon2d$");
}

Try / catch

try {
    return Argon2EncodingUtils.decode(hash);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Invalid algorithm type")) {
        throw new UnsupportedHashAlgorithmException(hash, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling decode() on a hash whose second '$'-delimited segment is not exactly "argon2d", "argon2i", or "argon2id" — e.g. a bcrypt '$2a$...' string, an scrypt or PBKDF2 hash, or a hash with a case mismatch like 'Argon2id'.

Common situations: Feeding non-Argon2 hashes to Argon2PasswordEncoder.matches() during a password-migration; hand-edited hash strings; case-sensitivity mistakes when normalizing hashes.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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