jwtk/jjwt · error · IllegalArgumentException

key must be an instance of . Type found

Error message

${msgPrefix}${type} key must be an instance of ${clazz.getName()}. Type found: ${key.getClass().getName()}

What it means

KeyPairs.assertKey verifies that a key handed to a KeyPairBuilder (via getKey) is an instance of the expected key class (e.g. RSAPrivateKey, ECPublicKey). If not, it throws IllegalArgumentException stating the required class and the actual type found. The 'private'/'public' prefix in the message identifies which half of the pair failed the check.

Solutions

  1. Read the required class name in the message and ensure the key implements it (e.g. java.security.interfaces.RSAPrivateKey).
  2. Generate/load keys with the correct algorithm: KeyPairGenerator.getInstance("RSA") for RSA, "EC" for EC.
  3. Swap the arguments if private/public were transposed.
  4. If the key is from a provider wrapper, extract the underlying key via its getFormat/encoding or use the provider's native interface.

Example fix

// before
KeyPair kp = KeyPairGenerator.getInstance("EC").generateKeyPair();
Jwks.builder().keyPair(kp).privateKey(kp.getPublic()); // wrong slot

// after
Jwks.builder().keyPair(kp)
    .privateKey((ECPrivateKey) kp.getPrivate())
    .publicKey((ECPublicKey) kp.getPublic()).build();
Defensive patterns

Strategy: type-guard

Validate before calling

boolean isRsaKeyPair(KeyPair kp) {
    return kp.getPublic() instanceof java.security.interfaces.RSAPublicKey
        && kp.getPrivate() instanceof java.security.interfaces.RSAPrivateKey;
}

Type guard

if (key instanceof java.security.interfaces.RSAPrivateKey rsa) {
    builder.privateKey(rsa);
} else {
    throw new IllegalArgumentException("Expected RSAPrivateKey, got " + key.getClass().getName());
}

Try / catch

try {
    jwk = builder.build();
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("key must be an instance of")) {
        // regenerate or cast keys to the expected interface
    } else throw e;
}

Prevention

When it happens

Trigger: Calling KeyPairs (e.g. Jwks.builder().keyPair(...).privateKey(key) or .publicKey(key)) with a key of the wrong type/interface, such as passing a generic PrivateKey or a DH key where an RSA key is required, or swapping private/public arguments.

Common situations: Passing keys loaded from a keystore under the wrong algorithm (EC key where RSA expected); using a PKCS11 provider key that implements a different interface; accidentally passing the public key to the privateKey slot; keys of unsupported algorithms (Edwards vs EC confusion).

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/e3dc21bd15ab1a9b. Report an issue: GitHub.

Appendix: source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/KeyPairs.java:57

        }
    }

    public static <K> K getKey(KeyPair pair, Class<K> clazz) {
        Assert.notNull(pair, "KeyPair cannot be null.");
        String prefix = familyPrefix(clazz) + "KeyPair ";
        boolean isPrivate = PrivateKey.class.isAssignableFrom(clazz);
        Key key = isPrivate ? pair.getPrivate() : pair.getPublic();
        return assertKey(key, clazz, prefix);
    }

    public static <K> K assertKey(Key key, Class<K> clazz, String msgPrefix) {
        Assert.notNull(key, "Key argument cannot be null.");
        Assert.notNull(clazz, "Class argument cannot be null.");
        String type = key instanceof PrivateKey ? "private" : "public";
        if (!clazz.isInstance(key)) {
            String msg = msgPrefix + type + " key must be an instance of " + clazz.getName() +
                ". Type found: " + key.getClass().getName();
            throw new IllegalArgumentException(msg);
        }
        return clazz.cast(key);
    }
}

View on GitHub (pinned to fb71496164)