keycloak/keycloak · error · RuntimeException

Error while updating policy [{}]. Client Scope [{}] could no

Error message

Error while updating policy [{}]. Client Scope [{}] could not be found.

What it means

Thrown by ClientScopePolicyProviderFactory.updateClientScopes() when a referenced client scope cannot be resolved by name (realm.getClientScopesStream().filter(name == clientScopeName)) nor by id (realm.getClientScopeById(clientScopeName)). NOTE: there is a source bug — the message string is "Client Scope [" + "] could not be found." which omits the clientScopeName variable, so the brackets are always empty in the rendered message. The actual offending scope name is in the local variable clientScopeName but never interpolated.

Source

Thrown at authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/clientscope/ClientScopePolicyProviderFactory.java:238

    }

    private void updateClientScopes(Policy policy, AuthorizationProvider authorization,
        Set<ClientScopeDefinition> clientScopes) {
        RealmModel realm = authorization.getRealm();
        Set<ClientScopePolicyRepresentation.ClientScopeDefinition> updatedClientScopes = new HashSet<>();

        if (clientScopes != null) {
            for (ClientScopePolicyRepresentation.ClientScopeDefinition definition : clientScopes) {
                String clientScopeName = definition.getId();
                ClientScopeModel clientScope = realm.getClientScopesStream()
                    .filter(scope -> scope.getName().equals(clientScopeName)).findAny().orElse(null);

                if (clientScope == null) {
                    clientScope = realm.getClientScopeById(clientScopeName);
                }

                if (clientScope == null) {
                    throw new RuntimeException(
                        "Error while updating policy [" + policy.getName() + "]. Client Scope [" + "] could not be found.");
                }

                definition.setId(clientScope.getId());
                updatedClientScopes.add(definition);
            }
        }

        try {
            policy.putConfig("clientScopes", JsonSerialization.writeValueAsString(updatedClientScopes));
        } catch (IOException e) {
            throw new RuntimeException("Failed to serialize client scopes", e);
        }
    }
}

View on GitHub (pinned to 66c7e15a37)

Solutions

  1. Since the message is empty, log the inbound representation's clientScope names/ids yourself before calling update to identify the bad reference.
  2. Validate each definition.getId() resolves via name or id in the target realm before update.
  3. Correct typos or remove stale references; ensure scopes exist (create them first if importing).

Example fix

// before: update throws with an empty 'Client Scope []' (source bug hides the name)
rep.setClientScopes(Collections.singleton(definitionWithName("public-scope-typo")));
authz.policies().update(rep);

// after: validate each scope reference before update, surfacing the real name
RealmModel realm = authorization.getRealm();
for (ClientScopeDefinition d : rep.getClientScopes()) {
    String n = d.getId();
    boolean exists = realm.getClientScopesStream().anyMatch(s -> s.getName().equals(n))
                 || realm.getClientScopeById(n) != null;
    if (!exists) throw new IllegalArgumentException("unknown client scope: " + n);
}
authz.policies().update(rep);
Defensive patterns

Strategy: validation

Validate before calling

// Validate each client scope reference resolves (name then id) before update
RealmModel realm = authorization.getRealm();
for (ClientScopeDefinition d : rep.getClientScopes()) {
    String n = d.getId();
    boolean exists = realm.getClientScopesStream().anyMatch(s -> s.getName().equals(n))
                 || realm.getClientScopeById(n) != null;
    if (!exists) throw new IllegalArgumentException("unknown client scope: " + n);
}

Type guard

private boolean clientScopeResolves(RealmModel realm, String nameOrId) {
    return realm.getClientScopesStream().anyMatch(s -> s.getName().equals(nameOrId))
        || realm.getClientScopeById(nameOrId) != null;
}

Try / catch

// The exception message is buggy (empty brackets); validate yourself.
for (ClientScopeDefinition d : rep.getClientScopes()) {
    if (!clientScopeResolves(realm, d.getId()))
        throw new IllegalArgumentException("unknown client scope: " + d.getId());
}
authz.policies().update(rep);

Prevention

When it happens

Trigger: Creating or updating a 'client-scope' policy whose clientScopes reference a scope name or id that does not exist in the realm. The lookup tries name first, then falls back to id; both failing raises this. Because of the message bug, you cannot read the offending name from the exception text — you must inspect the request/representation directly.

Common situations: Typo in a client scope name; the client scope was deleted after the policy was last edited; cross-realm confusion; using an id where a name is expected (or vice-versa) that doesn't match either; import referencing scopes not present in the target realm.

Related errors


AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14). Data as JSON: /api/errors/547dcb68f6281f89. Report an issue: GitHub.