jwtk/jjwt · error · MalformedKeyException
Unable to create JWK: ${iae.getMessage()}
Error message
Unable to create JWK: ${iae.getMessage()} What it means
When build() delegates to jwkFactory.createJwk and an IllegalArgumentException escapes, the builder translates it into MalformedKeyException with an 'Unable to create JWK' message. It means the supplied JWK fields were present but invalid (missing required members for the kty, wrong formats, or failed validation).
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/AbstractJwkBuilder.java:158
@Override
public J build() {
//should always exist as there isn't a way to set it outside the constructor:
Assert.stateNotNull(this.DELEGATE, "JwkContext should always be non-null");
K key = this.DELEGATE.getKey();
if (key == null && isEmpty()) {
String msg = "A " + Key.class.getName() + " or one or more name/value pairs must be provided to create a JWK.";
throw new IllegalStateException(msg);
}
try {
this.opsPolicy.validate(this.DELEGATE.get(AbstractJwk.KEY_OPS));
return jwkFactory.createJwk(this.DELEGATE);
} catch (IllegalArgumentException iae) {
//if we get an IAE, it means the builder state wasn't configured enough in order to create
String msg = "Unable to create JWK: " + iae.getMessage();
throw new MalformedKeyException(msg, iae);
}
}
static class DefaultSecretJwkBuilder extends AbstractJwkBuilder<SecretKey, SecretJwk, SecretJwkBuilder>
implements SecretJwkBuilder {
public DefaultSecretJwkBuilder(JwkContext<SecretKey> ctx) {
super(ctx);
// assign a standard algorithm if possible:
Key key = Assert.notNull(ctx.getKey(), "SecretKey cannot be null.");
DefaultMacAlgorithm mac = DefaultMacAlgorithm.findByKey(key);
if (mac != null) {
algorithm(mac.getId());
}
}
}
}
View on GitHub (pinned to fb71496164)
Solutions
- Read iae.getMessage() from the cause to see which field/validation failed.
- Ensure all RFC 7518-required members for the kty are present and valid base64url.
- Use Jwks.parser().parse(json) for external JWK data so full validation runs.
- Wrap build() in try-catch for MalformedKeyException when handling untrusted input.
Example fix
// before
Jwk<?> jwk = Jwks.builder().put("kty", "RSA").build();
// after
Jwk<?> jwk = Jwks.builder().put("kty", "RSA").put("n", nB64).put("e", eB64).build(); Defensive patterns
Strategy: validation
Validate before calling
// ensure required members exist for kty before building
Set<String> required = kty.equals("RSA") ? Set.of("n","e") : Set.of("kty","crv","x","y");
if (!jwkMap.keySet().containsAll(required)) throw new MalformedKeyException("missing: " + new HashSet<>(required) ); Try / catch
try { jwk = builder.build(); }
catch (MalformedKeyException e) { log.warn("Bad JWK from source: {}", e.getMessage()); reject(e); } Prevention
- Validate external JWK fields before constructing builders.
- Use Jwks.parser() for untrusted JWK JSON.
- Check for typos in member names (kty, n, e, x, y, crv).
When it happens
Trigger: Building a JWK from name/value pairs where a required field for the key type is missing or malformed (e.g. RSA builder without 'n' or 'e', non-base64url values, invalid key-ops combination caught by ops validation).
Common situations: Manually assembling JWK JSON fields; parsing third-party JWK sets with incomplete entries; typo'd field names so a required member appears absent.
Related errors
- A ${Key.class.getName()} or one or more name/value pairs mus
- Unrecognized JWA EC curve id '${jwaCurveId}'
- Unable to create ${type.getSimpleName()} from JWK ${ctx}: ${
- Unsupported JwkContext.
- JWKs are immutable and may not be modified.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/31c6bc7d8b03e92f.
Report an issue: GitHub.