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.

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.

Appendix: 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)