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

JWK kty value cannot be empty.

Error message

JWK kty value cannot be empty.

What it means

Thrown by JwkConverter.applyFrom when a JWK's kty member is a String but empty. RFC 7517 requires kty to be a meaningful key-type identifier; an empty string cannot identify a key type, so the JWK is rejected as malformed (MalformedKeyException).

Source

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

        // 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() + ".";
                throw new IllegalArgumentException(msg);
            }
            String skey = (String) key;
            builder.add(skey, entry.getValue());
        }
        Jwk<?> jwk = builder.build();

        if (desiredType.isInstance(jwk)) {
            return desiredType.cast(jwk);

View on GitHub (pinned to fb71496164)

Solutions

  1. Supply a valid kty value ("EC", "RSA", "oct", "OKP")
  2. Trim/default handling in the code that generates or forwards JWK JSON
  3. Validate the key JSON before passing it to the jjwt Jwks APIs

Example fix

// before
{"kty":"", "crv":"P-256", "x":"...", "y":"..."}
// after
{"kty":"EC", "crv":"P-256", "x":"...", "y":"..."}
Defensive patterns

Strategy: validation

Validate before calling

String kty = (String) jwkMap.get("kty"); if (kty == null || kty.isBlank()) { throw new IllegalArgumentException("kty must be non-empty"); }

Type guard

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

Try / catch

try { jwk = parser.parse(json); } catch (MalformedKeyException e) { log.error("Empty kty: {}", e.getMessage()); }

Prevention

When it happens

Trigger: JWK JSON such as {"kty":""} or {"kty":" "} passed to JWK parsing/conversion.

Common situations: Placeholder values left in generated config; field stripped by a template engine; upstream key provider returning empty kty.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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