jwtk/jjwt · error · java.lang.IllegalArgumentException
JWK must be a Map<String,?> (JSON Object). Type found: ${typ
Error message
JWK must be a Map<String,?> (JSON Object). Type found: ${type}. What it means
JwkConverter.convertFrom expects the raw parsed JSON value for a JWK to be a Map (JSON object), since JWKs are defined as JSON objects per RFC 7517. If the value is any other type (string, number, list, null), an IllegalArgumentException is thrown stating the actual Java type found.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java:134
private IllegalArgumentException unexpectedIAE(Jwk<?> jwk) {
String desired = typeString(this.desiredType);
String jwkType = typeString(jwk);
String msg = "Value must be " + articleFor(desired) + " " + desired + ", not " +
articleFor(jwkType) + " " + jwkType + ".";
return new IllegalArgumentException(msg);
}
@Override
public T applyFrom(Object o) {
Assert.notNull(o, "JWK cannot be null.");
if (desiredType.isInstance(o)) {
return desiredType.cast(o);
} else if (o instanceof Jwk<?>) {
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);View on GitHub (pinned to fb71496164)
Solutions
- Ensure the JWK value in the header/document is a JSON object like {"kty":"EC",...}, not a string or array.
- If you meant to pass a JWK Set, use the appropriate JWKS parser API for `keys` arrays instead of single-JWK conversion.
- Regenerate the token with a compliant producer; do not manually quote the JWK JSON.
- Validate the JSON document shape before parsing (jwk must be an object).
Example fix
// before: JWK serialized as a string
{"jwk": "{\"kty\":\"EC\"...}"}
// after: JWK as a JSON object
{"jwk": {"kty":"EC","crv":"P-256","x":"...","y":"..."}} Defensive patterns
Strategy: type-guard
Validate before calling
Object jwk = header.get("jwk");
if (!(jwk instanceof Map)) {
throw new IllegalArgumentException("jwk header must be a JSON object, got: " + (jwk == null ? "null" : jwk.getClass().getName()));
} Type guard
boolean isJwkObject(Object o) {
return o instanceof Map && ((Map<?,?>)o).get("kty") instanceof String;
} Try / catch
try {
Jwk<?> jwk = Jwks.parser().build().parse(json);
} catch (IllegalArgumentException e) {
// JWK value was not a JSON object; fix producer output
} Prevention
- Never serialize a JWK as a JSON string; keep it as an object
- Validate JWKS documents: each entry in `keys` must be an object
- Parse JWKS with the JWKS parser API, not the single-JWK API
- Validate token header shapes with a schema before parsing
When it happens
Trigger: Parsing a JWT/JWKS where the `jwk` header value or a JWKS entry is not a JSON object — e.g. `"jwk": "string"`, a JSON array of keys passed where a single key object is expected, or deserializing nested structures that collapse to non-Map types.
Common situations: Hand-written tokens where the jwk header was serialized as a string instead of an object; JWKS documents whose `keys` array contains non-object entries; a producer library emitting a JWK wrapped in quotes; confusion between a JWK Set and a single JWK.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Deserialized data is not a JSON Object; cannot create Map<St
- Unsupported value type. Expected: ${type.getName()}, found:
- Unrelated key operations are not allowed. KeyOperation [${in
- JWK is missing required kty parameter.
- JWK kty value cannot be null.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/de9869d859ef3b7b.
Report an issue: GitHub.