jwtk/jjwt · error · io.jsonwebtoken.security.MalformedKeySetException
JWK Set keys value cannot be null.
Error message
JWK Set keys value cannot be null.
What it means
Thrown by JwkSetConverter.applyFrom when the JWK Set's keys member exists but its value is null. RFC 7517 §5 requires keys to hold the array of JWKs, so a null value is treated as a malformed JWK Set and rejected with MalformedKeySetException.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/JwkSetConverter.java:92
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);
}
int size = Collections.size((Collection<?>) val);
if (size == 0) {
String msg = "JWK Set " + PARAM + " collection cannot be empty.";
throw new MalformedKeySetException(msg);
}
// Copy values so we don't mutate the original input
Map<String, Object> src = new LinkedHashMap<>(Collections.size((Map<?, ?>) o));
for (Map.Entry<?, ?> entry : ((Map<?, ?>) o).entrySet()) {
Object key = Assert.notNull(entry.getKey(), "JWK Set map key cannot be null.");
if (!(key instanceof String)) {
String msg = "JWK Set map keys must be Strings. Encountered key '" + key + "' of type " +View on GitHub (pinned to fb71496164)
Solutions
- Provide a non-null JSON array for "keys", e.g. [] with at least one JWK
- Check the upstream JWKS source for why keys is null
- Sanitize input to reject/replace null-valued fields before parsing
Example fix
// before
{"keys": null}
// after
{"keys":[{"kty":"EC","crv":"P-256","x":"...","y":"..."}]} Defensive patterns
Strategy: validation
Validate before calling
Object keys = m.get("keys"); if (keys == null) { throw new IllegalArgumentException("JWKS 'keys' must not be null"); } Type guard
boolean hasNonNullKeys(Map<?,?> m) { return m != null && m.get("keys") != null; } Try / catch
try { jwkSet = jwkSetConverter.applyFrom(map); } catch (MalformedKeySetException e) { log.error("JWKS keys null: {}", e.getMessage()); } Prevention
- Treat upstream keys:null as an upstream provisioning failure
- Sanitize null-valued members before parsing
When it happens
Trigger: Parsing a JWKS map like {"keys": null} or programmatically building the set with a null keys value.
Common situations: Template/serialization output emitting explicit nulls; upstream JWKS endpoint returning keys:null when it has no keys; placeholder config.
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
- JWK kty value cannot be null.
- Missing required keys parameter.
- JWK Set keys collection cannot be empty.
- JWK is missing required kty parameter.
- JWK kty value cannot be empty.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/8eb6161e7e48ca4d.
Report an issue: GitHub.