jwtk/jjwt · error · io.jsonwebtoken.security.MalformedKeySetException
JWK Set keys collection cannot be empty.
Error message
JWK Set keys collection cannot be empty.
What it means
Thrown by JwkSetConverter.applyFrom when the JWK Set's keys member is an empty collection. A JWK Set must contain at least one key to be usable, so an empty keys array is rejected as a malformed JWK Set (MalformedKeySetException).
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/JwkSetConverter.java:102
// 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 " +
key.getClass().getName();
throw new IllegalArgumentException(msg);
}
String skey = (String) key;
src.put(skey, entry.getValue());
}
Set<Jwk<?>> jwks = new LinkedHashSet<>(size);
int i = 0; // keep track of which element fails (if any)
for (Object candidate : ((Collection<?>) val)) {View on GitHub (pinned to fb71496164)
Solutions
- Ensure the JWKS source contains at least one key
- Check the issuer/JWKS endpoint for provisioning or outage issues
- Treat empty keys as retryable/re-fetchable upstream (cache refresh) and surface a clear error to users
Example fix
// before
{"keys":[]}
// after
{"keys":[{"kty":"RSA","n":"...","e":"AQAB","kid":"key-1","alg":"RS256"}]} Defensive patterns
Strategy: validation
Validate before calling
Collection<?> keys = (Collection<?>) m.get("keys"); if (keys == null || keys.isEmpty()) { throw new IllegalArgumentException("JWKS must contain at least one key"); } Type guard
boolean hasAtLeastOneKey(Map<?,?> m) { Object k = m == null ? null : m.get("keys"); return k instanceof Collection<?> c && !c.isEmpty(); } Try / catch
try { jwkSet = Jwks.setParser().build().parse(json); } catch (MalformedKeySetException e) { scheduleJwksRefresh(); log.warn("Empty JWKS from upstream: {}", e.getMessage()); } Prevention
- Monitor upstream JWKS endpoints for empty responses
- Cache last-known-good keys and re-fetch on empty results
- Confirm issuer URL/key provisioning before deployment
When it happens
Trigger: Parsing {"keys":[]} or building a JWK Set with an empty collection.
Common situations: IdP JWKS endpoint returning an empty array during outages or before keys are provisioned; key rotation removing all keys; misconfigured issuer URL returning a valid-but-empty document.
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
- JWK kty value cannot be empty.
- Missing required keys parameter.
- JWK Set keys value cannot be null.
- 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/e796ef6b1c60e423.
Report an issue: GitHub.