jwtk/jjwt · error · IllegalArgumentException
Unrelated key operations are not allowed. KeyOperation [${in
Error message
Unrelated key operations are not allowed. KeyOperation [${inner}] is unrelated to [${operation}]. What it means
IllegalArgumentException from DefaultKeyOperationPolicy.validate when a set of KeyOperations contains operations that are unrelated to each other and the policy does not allow unrelated operations. JWK key_ops entries must be mutually related (e.g. all encryption-direction operations).
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/DefaultKeyOperationPolicy.java:51
Assert.notEmpty(ops, "KeyOperation collection cannot be null or empty.");
this.ops = Collections.immutable(ops);
this.allowUnrelated = allowUnrelated;
}
@Override
public Collection<KeyOperation> getOperations() {
return this.ops;
}
@Override
public void validate(Collection<? extends KeyOperation> ops) {
if (allowUnrelated || Collections.isEmpty(ops)) return;
for (KeyOperation operation : ops) {
for (KeyOperation inner : ops) {
if (!operation.isRelated(inner)) {
String msg = "Unrelated key operations are not allowed. KeyOperation [" + inner +
"] is unrelated to [" + operation + "].";
throw new IllegalArgumentException(msg);
}
}
}
}
@Override
public int hashCode() {
int hash = Boolean.valueOf(this.allowUnrelated).hashCode();
KeyOperation[] ops = this.ops.toArray(new KeyOperation[0]);
hash = 31 * hash + Objects.nullSafeHashCode((Object[]) ops);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (!(obj instanceof DefaultKeyOperationPolicy)) {
return false;View on GitHub (pinned to fb71496164)
Solutions
- Restrict the JWK's keyOps set to related operations (e.g. only ENCRYPT/DECRYPT or only SIGN/VERIFY).
- Create the policy with allowUnrelated=true if you intentionally permit unrelated combinations.
- Validate the operation list against KeyOperation.isRelated pairs before building the key.
- Fix the source of aggregated operations so unrelated ones are not merged into one key.
Example fix
// before Jwts.builder().keys().builder() .keyOperations(EnumSet.of(KeyOperation.ENCRYPT, KeyOperation.SIGN)).build(); // after Jwts.builder().keys().builder() .keyOperations(EnumSet.of(KeyOperation.ENCRYPT, KeyOperation.DECRYPT)).build();
Defensive patterns
Strategy: validation
Validate before calling
boolean allRelated(Set<KeyOperation> ops) {
for (KeyOperation a : ops) for (KeyOperation b : ops)
if (!a.isRelated(b)) return false;
return true;
} Try / catch
try {
builder.keyOperations(ops);
} catch (IllegalArgumentException e) {
logger.error("Unrelated key_ops: {}", e.getMessage());
ops = relatedSubset(ops); // e.g. keep only encryption-direction ops
} Prevention
- Group operations by direction: {encrypt,decrypt,wrapKey,unwrapKey} vs {sign,verify}
- Never merge key_ops sets from different keys
- Build operation sets from named constants per key purpose
When it happens
Trigger: Building a JWK with keyOps containing unrelated operations, e.g. KeyOperations.ENCRYPT combined with KeyOperations.VERIFY, while the policy's allowUnrelated flag is false.
Common situations: Copying key_ops values from multiple different keys into one; typo'ing or mixing encrypt/decrypt-direction and sign/verify-direction operations; programmatically aggregating permitted operations from several sources.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Either a Key instance or a kty value is required to create a
- Unable to derive ECPublicKey from ECPrivateKey: ${e.getMessa
- The specified ECKey curve does not match a JWA standard curv
- ECPublicKey's ECPoint does not exist on elliptic curve '%s'
- EC JWK x,y coordinates do not exist on elliptic curve '%s'.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/5cdb339f6c3f8b4a.
Report an issue: GitHub.