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

  1. Restrict the JWK's keyOps set to related operations (e.g. only ENCRYPT/DECRYPT or only SIGN/VERIFY).
  2. Create the policy with allowUnrelated=true if you intentionally permit unrelated combinations.
  3. Validate the operation list against KeyOperation.isRelated pairs before building the key.
  4. 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

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


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/5cdb339f6c3f8b4a. Report an issue: GitHub.