jwtk/jjwt · error · InvalidKeyException

Unable to create from JWK

Error message

Unable to create ${type.getSimpleName()} from JWK ${ctx}: ${e.getMessage()}

What it means

AbstractFamilyJwkFactory.apply wraps exceptions thrown while converting a JWK context into a typed Jwk/Key. Any non-KeyException failure becomes an InvalidKeyException prefixed with the target type and JWK context summary. It indicates malformed or inconsistent JWK fields that broke key reconstruction.

Solutions

  1. Validate that all JWK fields are valid base64url strings of the expected length for the curve/modulus.
  2. Confirm the 'kty' matches the concrete builder used (e.g. ECPublicJwkBuilder for EC keys).
  3. Catch InvalidKeyException and log the wrapped cause (e.getCause()) for the underlying failure.
  4. Regenerate or re-export the key if the material is corrupt.

Example fix

// before
try { Jwk<?> jwk = Jwks.parser().build().parse(json); }
catch (Exception e) { log.error(e.getMessage()); }
// after
try { Jwk<?> jwk = Jwks.parser().build().parse(json); }
catch (InvalidKeyException e) { log.error("JWK invalid", e.getCause()); }
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check base64url decodability of JWK fields
Base64.getUrlDecoder().decode(jwk.getString("n"));

Try / catch

try { Jwk<?> jwk = factory.apply(ctx); }
catch (InvalidKeyException e) { log.error("JWK {} invalid: {}", e.getMessage(), e.getCause()); }

Prevention

When it happens

Trigger: Calling Jwks.builder().build() or parsing a JWK where an arithmetic/decoding error occurs inside the type-specific factory (e.g. base64url-decoded coordinates of the wrong length, BigInteger conversion failures).

Common situations: JWK JSON with truncated or non-base64url 'n'/'e'/'x'/'y' values; mismatched kty vs fields; copying keys between systems corrupting values.

Related errors


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

Appendix: source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/AbstractFamilyJwkFactory.java:94

    protected String getKeyFactoryJcaName(final JwkContext<?> ctx) {
        String jcaName = KeysBridge.findAlgorithm(ctx.getKey());
        return Strings.hasText(jcaName) ? jcaName : getId();
    }

    protected <T extends Key> T generateKey(final JwkContext<?> ctx, final Class<T> type, final CheckedFunction<KeyFactory, T> fn) {
        String jcaName = getKeyFactoryJcaName(ctx);
        JcaTemplate template = new JcaTemplate(jcaName, ctx.getProvider(), ctx.getRandom());
        return template.withKeyFactory(new CheckedFunction<KeyFactory, T>() {
            @Override
            public T apply(KeyFactory instance) {
                try {
                    return fn.apply(instance);
                } catch (KeyException keyException) {
                    throw keyException; // propagate
                } catch (Exception e) {
                    String msg = "Unable to create " + type.getSimpleName() + " from JWK " + ctx + ": " + e.getMessage();
                    throw new InvalidKeyException(msg, e);
                }
            }
        });
    }

    @Override
    public final J createJwk(JwkContext<K> ctx) {
        Assert.notNull(ctx, "JwkContext argument cannot be null.");
        if (!supports(ctx)) { //should be asserted by caller, but assert just in case:
            String msg = "Unsupported JwkContext.";
            throw new IllegalArgumentException(msg);
        }
        K key = ctx.getKey();
        if (key != null) {
            ctx.setType(this.ktyValue);
            return createJwkFromKey(ctx);
        } else {
            return createJwkFromValues(ctx);

View on GitHub (pinned to fb71496164)