jwtk/jjwt · error · java.lang.IllegalArgumentException

Value must be a Map<String,?> (JSON Object). Type found: ${t

Error message

Value must be a Map<String,?> (JSON Object). Type found: ${type}.

What it means

JwkSetConverter.applyFrom requires its input to be a Map (JSON Object) representing a JWK Set, or an existing JwkSet. If the value is neither, IllegalArgumentException is thrown naming the actual type found.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/JwkSetConverter.java:79

    public boolean isIgnoreUnsupported() {
        return ignoreUnsupported;
    }

    @Override
    public Object applyTo(JwkSet jwkSet) {
        return jwkSet;
    }

    @Override
    public JwkSet applyFrom(Object o) {
        Assert.notNull(o, "Value cannot be null.");
        if (o instanceof JwkSet) {
            return (JwkSet) o;
        }
        if (!(o instanceof Map)) {
            String msg = "Value must be a Map<String,?> (JSON Object). Type found: " + o.getClass().getName() + ".";
            throw new IllegalArgumentException(msg);
        }
        final Map<?, ?> m = Collections.immutable((Map<?, ?>) o);

        // mandatory for all JWK Sets: https://datatracker.ietf.org/doc/html/rfc7517#section-5
        // no need for builder parameter type conversion overhead if this isn't present:
        if (Collections.isEmpty(m) || !m.containsKey(PARAM.getId())) {
            String msg = "Missing required " + PARAM + " parameter.";
            throw new MalformedKeySetException(msg);
        }
        Object val = m.get(PARAM.getId());
        if (val == null) {
            String msg = "JWK Set " + PARAM + " value cannot be null.";
            throw new MalformedKeySetException(msg);
        }
        if (!(val instanceof Collection)) {
            String msg = "JWK Set " + PARAM + " value must be a Collection (JSON Array). Type found: " +
                    val.getClass().getName();
            throw new MalformedKeySetException(msg);

View on GitHub (pinned to fb71496164)

Solutions

  1. Pass the full JWKS document as a Map: {"keys":[...]} (parse the JSON string first if needed)
  2. If you have a List of keys, wrap it: Map.of("keys", keyList)
  3. Use the appropriate Jwks parser API that accepts raw JSON text rather than pre-conversion

Example fix

// before
jwkSetConverter.applyFrom(keysArray); // List, not Map
// after
jwkSetConverter.applyFrom(Map.of("keys", keysArray));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(value instanceof Map)) { throw new IllegalArgumentException("JWK Set input must be a Map"); }

Type guard

boolean isJwkSetShape(Object o) { return o instanceof JwkSet || (o instanceof Map<?,?> m && m.containsKey("keys")); }

Try / catch

try { JwkSet set = jwkSetConverter.applyFrom(obj); } catch (IllegalArgumentException e) { log.error("Not a JWK Set object: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Passing a String, List, InputStream, or other non-Map object directly to JWK Set conversion (e.g. passing a parsed 'keys' array instead of the wrapping object).

Common situations: Passing the raw JWKS 'keys' array instead of the full {"keys":[...]} document; passing unparsed JSON text instead of a parsed Map.

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/bd81cfbe3c720494. Report an issue: GitHub.