xpipe-io/xpipe · error · IllegalArgumentException

Scope ${scope} is not supported

Error message

Scope ${scope} is not supported

What it means

MultiPrincipalSecret.with(secret, scope) re-encrypts the secret for a given DataStoreAccessScope, but only scopes for which supportsScopeEncryption(scope) is true are supported. Passing any other scope throws this IllegalArgumentException. It prevents silently producing a secret that cannot be used for that scope.

Source

Thrown at app/src/main/java/io/xpipe/app/secret/MultiPrincipalSecret.java:181

    public static MultiPrincipalSecret of(SecretValue internalSecret, Set<EncryptionPrincipal> principals) {
        for (EncryptionPrincipal principal : principals) {
            if (!principal.isAccessible()) {
                throw new IllegalArgumentException("Principal " + principal.getName() + " is not accessible");
            }
        }

        var l = new ArrayList<Entry>();
        for (EncryptionPrincipal principal : principals) {
            var enc = AesSecretValue.encrypt(internalSecret.getSecret(), principal.getSecretKey());
            l.add(new Entry(principal, enc.getEncryptedValue(), 1, EncryptionToken.of(principal)));
        }
        return new MultiPrincipalSecret(l, internalSecret.inPlace());
    }

    public MultiPrincipalSecret with(InPlaceSecretValue secret, DataStoreAccessScope scope) {
        if (!supportsScopeEncryption(scope)) {
            throw new IllegalArgumentException("Scope " + scope + " is not supported");
        }

        var secretUnchanged = secret == null || Arrays.equals(secret.getSecret(), this.secret.getSecret());
        if (secretUnchanged && getScope().equals(scope) && isScopeValid()) {
            return this;
        }

        var iteration = getMaxIteration();
        var l = new ArrayList<Entry>();
        for (EncryptionPrincipal principal : scope.getPrincipals()) {
            var existingEntry = entries.stream()
                    .filter(entry -> entry.getPrincipal().equals(principal))
                    .findFirst();

            // Keep existing entry if possible if not accessible
            if (!principal.isAccessible()) {
                if (existingEntry.isPresent()) {
                    l.add(existingEntry.get());

View on GitHub (pinned to d85ca821ba)

Solutions

  1. Check supportsScopeEncryption(scope) before calling with() and handle unsupported scopes separately
  2. Use the scope instance obtained from the same store/secret API rather than a hand-built one
  3. Update code to a supported scope mapping after API changes

Example fix

// before
return secret.with(newSecret, scope);
// after
if (!secret.supportsScopeEncryption(scope)) {
    return secret; // or handle unsupported scope
}
return secret.with(newSecret, scope);
Defensive patterns

Strategy: validation

Validate before calling

if (!secret.supportsScopeEncryption(scope)) {
    throw new IllegalArgumentException("Scope " + scope + " not supported");
}

Try / catch

try { return secret.with(newSecret, scope); } catch (IllegalArgumentException e) { if (e.getMessage().contains("is not supported")) { /* handle unsupported scope */ } else throw e; }

Prevention

When it happens

Trigger: Calling with(secret, scope) (directly or via withUpdatedPrincipals) with a scope value not covered by supportsScopeEncryption — e.g. a scope enum/constant outside the supported set for this secret type.

Common situations: Passing the wrong DataStoreAccessScope constant after a refactor; constructing secrets for a store type whose scope is not encryptable; migrating code between scope enums.

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 xpipe-io/xpipe@d85ca821ba (2026-09-06). Data as JSON: /api/errors/935de4e771ddbeb6. Report an issue: GitHub.