keycloak/keycloak · error · IllegalArgumentException
Permission id must not be null
Error message
Permission id must not be null
What it means
Thrown by PolicyResource.update(UmaPermissionRepresentation) when the permission is non-null but getId() returns null. The permission ID is used directly in the URL path of the PUT request (policy endpoint + / + encodedId). Without it, the server cannot identify which policy to update.
Source
Thrown at authz/client/src/main/java/org/keycloak/authorization/client/resource/PolicyResource.java:90
try {
return callable.call();
} catch (Exception cause) {
return Throwables.retryAndWrapExceptionIfNecessary(callable, pat, "Error creating policy for resource [" + resourceId + "]", cause);
}
}
/**
* Updates an existing user-managed permission
*
* @param permission the permission to update
*/
public void update(final UmaPermissionRepresentation permission) {
if (permission == null) {
throw new IllegalArgumentException("Permission must not be null");
}
if (permission.getId() == null) {
throw new IllegalArgumentException("Permission id must not be null");
}
Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() throws Exception {
http.<Void>put(serverConfiguration.getPolicyEndpoint() + "/"+ encodePathAsIs(permission.getId()))
.authorizationBearer(pat.call())
.json(JsonSerialization.writeValueAsBytes(permission)).execute();
return null;
}
};
try {
callable.call();
} catch (Exception cause) {
Throwables.retryAndWrapExceptionIfNecessary(callable, pat, "Error updating policy for resource [" + resourceId + "]", cause);
}
}
View on GitHub (pinned to 66c7e15a37)
Solutions
- Load the existing permission via findById(id) first to get its server-assigned ID, then modify and update
- If the ID is known from another source, set it: permission.setId(existingId) before calling update()
Example fix
// before
UmaPermissionRepresentation perm = new UmaPermissionRepresentation();
perm.setName("Updated Policy");
policyResource.update(perm); // throws — no id
// after
UmaPermissionRepresentation perm = policyResource.findById(existingPolicyId);
perm.setName("Updated Policy");
policyResource.update(perm); Defensive patterns
Strategy: validation
Validate before calling
// Ensure permission has an ID before updating
UmaPermissionRepresentation permission = loadPermission();
if (permission == null || permission.getId() == null) {
throw new IllegalStateException(
"Cannot update UMA permission without a server-assigned ID");
}
policyResource.update(permission); Type guard
public static boolean hasValidPermissionId(UmaPermissionRepresentation permission) {
return permission != null && permission.getId() != null;
} Prevention
- Never manually construct a UmaPermissionRepresentation for update — always load it from the server first
- If deserializing from JSON, validate that the id field is present and non-null
When it happens
Trigger: Constructing a new UmaPermissionRepresentation locally (which has no server-assigned ID) and calling update() on it. Loading a permission from an external/serialized source where the id field was not populated.
Common situations: Confusing create() semantics with update() — building a fresh permission object and trying to update it. JSON deserialization that omits or misnames the id field.
Related errors
- Permission ticket must have a requester
- Permission ticket must have a resource
- Permission ticket must have a scope
- Permission ticket must have an id
- Permission must not be null
AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14).
Data as JSON: /api/errors/a58158e53d86dc60.
Report an issue: GitHub.