keycloak/keycloak · error · RuntimeException
Could not parse roles from config: [{}]
Error message
Could not parse roles from config: [{}] What it means
Thrown by RolePolicyProviderFactory.getRoles() when Jackson cannot parse the raw 'roles' JSON string from the policy config into a RoleDefinition[] array. getRoles() is called from toRepresentation(), so this fires when reading/viewing a role policy whose stored config JSON is malformed. The raw JSON string is included in the message for diagnosis.
Source
Thrown at authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java:208
@Override
public void close() {
}
@Override
public String getId() {
return ID;
}
private Set<RoleDefinition> getRoles(String rawRoles, RealmModel realm) {
if (rawRoles != null) {
try {
return Arrays.stream(JsonSerialization.readValue(rawRoles, RoleDefinition[].class))
.filter(definition -> getRole(definition, realm) != null)
.sorted()
.collect(Collectors.toCollection(LinkedHashSet::new));
} catch (IOException e) {
throw new RuntimeException("Could not parse roles from config: [" + rawRoles + "]", e);
}
}
return Collections.emptySet();
}
public static final Pattern UUID_PATTERN = Pattern.compile("[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}");
private RoleModel getRole(RolePolicyRepresentation.RoleDefinition definition, RealmModel realm) {
String roleName = definition.getId();
String clientId = null;
int clientIdSeparator = roleName.indexOf("/");
if (clientIdSeparator != -1) {
clientId = roleName.substring(0, clientIdSeparator);
roleName = roleName.substring(clientIdSeparator + 1);
}
View on GitHub (pinned to 66c7e15a37)
Solutions
- Inspect config['roles'] in the policy (via DB or admin API) and validate it with a JSON parser.
- Fix the JSON to match the expected RoleDefinition schema [{"id":"role-uuid","required":true}].
- If unrecoverable, delete and recreate the role policy through the admin console.
- If from a realm import, fix the source export file's role policy config.
Example fix
// before: config["roles"] = "[{id: 'broken'}]"
// after: config["roles"] = "[{\"id\":\"role-uuid\",\"required\":true}]" Defensive patterns
Strategy: try-catch
Validate before calling
// Before reading a role policy, validate the stored roles JSON
String rolesJson = policy.getConfig().get("roles");
if (rolesJson != null) {
try {
RoleDefinition[] defs = JsonSerialization.readValue(rolesJson, RoleDefinition[].class);
// valid — safe to call toRepresentation()
} catch (IOException e) {
logger.warn("Role policy config is corrupt: " + e.getMessage());
}
} Try / catch
try {
RolePolicyRepresentation rep = factory.toRepresentation(policy, authorization);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Could not parse roles from config")) {
logger.error("Corrupt role policy config for: " + policy.getName(), e);
// recreate the policy from scratch
} else {
throw e;
}
} Prevention
- Never hand-edit policy config JSON directly in the database.
- Always create and update role policies through the admin REST API or console.
- After version upgrades, validate existing policy configs on a staging instance.
When it happens
Trigger: GET .../policy/role/{policyId} for a role policy whose config['roles'] is corrupt JSON. Also triggered internally during evaluation when the role policy representation is resolved.
Common situations: Database-level corruption of the policy config. A failed migration or import leaving truncated/malformed JSON. Hand-editing the policy config directly in the DB. Version upgrade where the RoleDefinition schema changed without migration.
Related errors
- Failed to deserialize groups
- Failed to deserialize roles
- Failed to export role policy [{}]
- Role can't be specified multiple times - {}
- Failed to serialize roles
AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14).
Data as JSON: /api/errors/eaef963a42ec1790.
Report an issue: GitHub.