{"record":{"id":"ff0b7ae0d64bd3b2","repo":"keycloak/keycloak","slug":"failed-to-serialize-clients","errorCode":null,"errorMessage":"Failed to serialize clients","messagePattern":"Failed to serialize clients","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java","lineNumber":192,"sourceCode":"\n        for (String id : clients) {\n            ClientModel client = realm.getClientByClientId(id);\n\n            if (client == null) {\n                client = realm.getClientById(id);\n            }\n\n            if (client == null) {\n                throw new RuntimeException(\"Error while updating policy [\" + policy.getName()  + \"]. Client [\" + id + \"] could not be found.\");\n            }\n\n            updatedClients.add(client.getId());\n        }\n\n        try {\n            policy.putConfig(\"clients\", JsonSerialization.writeValueAsString(updatedClients));\n        } catch (IOException cause) {\n            throw new RuntimeException(\"Failed to serialize clients\", cause);\n        }\n    }\n\n    private Set<String> getClients(Policy policy) {\n        String clients = policy.getConfig().get(\"clients\");\n\n        if (clients != null) {\n            try {\n                return JsonSerialization.readValue(clients, Set.class);\n            } catch (IOException e) {\n                throw new RuntimeException(\"Could not parse clients [\" + clients + \"] from policy config [\" + policy.getName() + \"].\", e);\n            }\n        }\n\n        return Collections.emptySet();\n    }\n}\n","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/keycloak/keycloak/blob/66c7e15a3788de7764f07dd2558275a02770e16d/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java#L174-L210","documentation":"Thrown by ClientPolicyProviderFactory.updateClients() when JsonSerialization.writeValueAsString(updatedClients) throws IOException after the client set has been resolved and normalized to internal DB IDs. updatedClients is a Set<String> of client IDs, so this only fails on a Jackson/mapper fault, not on bad data — the data was already validated by the lookup loop. It is a terminal serialization failure during policy config persistence.","triggerScenarios":"Updating a client policy where all client references resolved successfully, but the final JSON serialization of the normalized ID set into the policy's 'clients' config key fails. Essentially never a data problem; indicates a broken ObjectMapper or an I/O error inside the serializer.","commonSituations":"A custom/overridden JsonSerialization ObjectMapper that cannot handle Set<String>; an SPI or extension replacing the mapper; concurrent classloader issues; an I/O fault during in-memory serialization (very rare).","solutions":["Inspect the wrapped IOException cause — it will reveal the Jackson-level failure.","Remove or fix any custom JsonSerialization/ObjectMapper override.","Retry the policy update; if it persists, isolate which client ID string (if any) breaks the mapper.","Confirm no extension is registering a custom serializer for String/Set."],"exampleFix":"// before: opaque 'Failed to serialize clients'\npolicy.putConfig(\"clients\", JsonSerialization.writeValueAsString(updatedClients));\n\n// after: use a standalone ObjectMapper to surface the real failure\ntry {\n    policy.putConfig(\"clients\", JsonSerialization.writeValueAsString(updatedClients));\n} catch (IOException cause) {\n    throw new RuntimeException(\"Failed to serialize clients \" + updatedClients, cause);\n}","handlingStrategy":"try-catch","validationCode":"// No data pre-check; this is a serializer fault. Confirm default ObjectMapper.\nreturn null;","typeGuard":null,"tryCatchPattern":"try {\n    authz.policies().update(rep);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().equals(\"Failed to serialize clients\")) {\n        log.error(\"Jackson could not serialize client id set {}\", resolvedIds, e.getCause());\n    }\n    throw e;\n}","preventionTips":["Do not override the global JsonSerialization/ObjectMapper with a custom one.","Ensure no SPI registers a custom serializer for Set/String.","Reproduce the serialization in isolation to confirm the mapper is stock."],"tags":["policy","client-policy","json","serialization","config"],"backgroundTag":null,"analyzedSha":"66c7e15a3788de7764f07dd2558275a02770e16d","analyzedAt":"2026-08-14T01:36:42.651Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}