{"record":{"id":"eaef963a42ec1790","repo":"keycloak/keycloak","slug":"could-not-parse-roles-from-config","errorCode":null,"errorMessage":"Could not parse roles from config: [{}]","messagePattern":"Could not parse roles from config: \\[(.+?)\\]","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java","lineNumber":208,"sourceCode":"    @Override\n    public void close() {\n\n    }\n\n    @Override\n    public String getId() {\n        return ID;\n    }\n\n    private Set<RoleDefinition> getRoles(String rawRoles, RealmModel realm) {\n        if (rawRoles != null) {\n            try {\n                return Arrays.stream(JsonSerialization.readValue(rawRoles, RoleDefinition[].class))\n                        .filter(definition -> getRole(definition, realm) != null)\n                        .sorted()\n                        .collect(Collectors.toCollection(LinkedHashSet::new));\n            } catch (IOException e) {\n                throw new RuntimeException(\"Could not parse roles from config: [\" + rawRoles + \"]\", e);\n            }\n        }\n\n        return Collections.emptySet();\n    }\n\n    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}\");\n\n    private RoleModel getRole(RolePolicyRepresentation.RoleDefinition definition, RealmModel realm) {\n        String roleName = definition.getId();\n        String clientId = null;\n        int clientIdSeparator = roleName.indexOf(\"/\");\n\n        if (clientIdSeparator != -1) {\n            clientId = roleName.substring(0, clientIdSeparator);\n            roleName = roleName.substring(clientIdSeparator + 1);\n        }\n","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/keycloak/keycloak/blob/66c7e15a3788de7764f07dd2558275a02770e16d/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java#L190-L226","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: config[\"roles\"] = \"[{id: 'broken'}]\"\n// after:  config[\"roles\"] = \"[{\\\"id\\\":\\\"role-uuid\\\",\\\"required\\\":true}]\"","handlingStrategy":"try-catch","validationCode":"// Before reading a role policy, validate the stored roles JSON\nString rolesJson = policy.getConfig().get(\"roles\");\nif (rolesJson != null) {\n    try {\n        RoleDefinition[] defs = JsonSerialization.readValue(rolesJson, RoleDefinition[].class);\n        // valid — safe to call toRepresentation()\n    } catch (IOException e) {\n        logger.warn(\"Role policy config is corrupt: \" + e.getMessage());\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    RolePolicyRepresentation rep = factory.toRepresentation(policy, authorization);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Could not parse roles from config\")) {\n        logger.error(\"Corrupt role policy config for: \" + policy.getName(), e);\n        // recreate the policy from scratch\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["keycloak","authorization","json-deserialization","role-policy","config-corruption"],"backgroundTag":null,"analyzedSha":"66c7e15a3788de7764f07dd2558275a02770e16d","analyzedAt":"2026-08-14T01:36:42.651Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}