jwtk/jjwt · error · io.jsonwebtoken.security.MalformedKeyException

JWK kty value cannot be null.

Error message

JWK kty value cannot be null.

What it means

applyFrom checks the value of the mandatory 'kty' parameter for null after confirming the key exists. A JWK whose 'kty' member is present but JSON null is malformed, so MalformedKeyException is thrown.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java:148

            throw unexpectedIAE((Jwk<?>) o);
        }
        if (!(o instanceof Map)) {
            String msg = "JWK must be a Map<String,?> (JSON Object). Type found: " + o.getClass().getName() + ".";
            throw new IllegalArgumentException(msg);
        }
        final Map<?, ?> map = Collections.immutable((Map<?, ?>) o);

        Parameter<String> param = AbstractJwk.KTY;
        // mandatory for all JWKs: https://datatracker.ietf.org/doc/html/rfc7517#section-4.1
        // no need for builder param type conversion overhead if this isn't present:
        if (Collections.isEmpty(map) || !map.containsKey(param.getId())) {
            String msg = "JWK is missing required " + param + " parameter.";
            throw new MalformedKeyException(msg);
        }
        Object val = map.get(param.getId());
        if (val == null) {
            String msg = "JWK " + param + " value cannot be null.";
            throw new MalformedKeyException(msg);
        }
        if (!(val instanceof String)) {
            String msg = "JWK " + param + " value must be a String. Type found: " + val.getClass().getName();
            throw new MalformedKeyException(msg);
        }
        String kty = (String) val;
        if (!Strings.hasText(kty)) {
            String msg = "JWK " + param + " value cannot be empty.";
            throw new MalformedKeyException(msg);
        }

        DynamicJwkBuilder<?, ?> builder = this.supplier.get();
        for (Map.Entry<?, ?> entry : map.entrySet()) {
            Object key = entry.getKey();
            Assert.notNull(key, "JWK map key cannot be null.");
            if (!(key instanceof String)) {
                String msg = "JWK map keys must be Strings. Encountered key '" + key + "' of type " +
                        key.getClass().getName() + ".";

View on GitHub (pinned to fb71496164)

Solutions

  1. Provide a non-null "kty" value such as "RSA", "EC", "oct", or "OKP"
  2. Sanitize the JSON before parsing to remove null-valued fields
  3. Log/inspect the source of the key data to find where the null originates

Example fix

// before
{"kty": null, "n": "...", "e": "AQAB"}
// after
{"kty": "RSA", "n": "...", "e": "AQAB"}
Defensive patterns

Strategy: validation

Validate before calling

Object kty = jwkMap.get("kty"); if (kty == null) { throw new IllegalArgumentException("JWK 'kty' must not be null"); }

Type guard

boolean hasNonNullKty(Map<String,?> m) { return m != null && m.get("kty") != null; }

Try / catch

try { jwk = jwkParser.parse(map); } catch (MalformedKeyException e) { log.error("JWK rejected: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Parsing JWK JSON like {"kty": null, ...} or building a JWK from a map where kty maps to null.

Common situations: Deserialization frameworks or template-generated JSON that emit explicit nulls; partial key material filled in programmatically.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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