keycloak/keycloak · error · RuntimeException
Failed to serialize clients
Error message
Failed to serialize clients
What it means
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.
Source
Thrown at authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/client/ClientPolicyProviderFactory.java:192
for (String id : clients) {
ClientModel client = realm.getClientByClientId(id);
if (client == null) {
client = realm.getClientById(id);
}
if (client == null) {
throw new RuntimeException("Error while updating policy [" + policy.getName() + "]. Client [" + id + "] could not be found.");
}
updatedClients.add(client.getId());
}
try {
policy.putConfig("clients", JsonSerialization.writeValueAsString(updatedClients));
} catch (IOException cause) {
throw new RuntimeException("Failed to serialize clients", cause);
}
}
private Set<String> getClients(Policy policy) {
String clients = policy.getConfig().get("clients");
if (clients != null) {
try {
return JsonSerialization.readValue(clients, Set.class);
} catch (IOException e) {
throw new RuntimeException("Could not parse clients [" + clients + "] from policy config [" + policy.getName() + "].", e);
}
}
return Collections.emptySet();
}
}
View on GitHub (pinned to 66c7e15a37)
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.
Example fix
// before: opaque 'Failed to serialize clients'
policy.putConfig("clients", JsonSerialization.writeValueAsString(updatedClients));
// after: use a standalone ObjectMapper to surface the real failure
try {
policy.putConfig("clients", JsonSerialization.writeValueAsString(updatedClients));
} catch (IOException cause) {
throw new RuntimeException("Failed to serialize clients " + updatedClients, cause);
} Defensive patterns
Strategy: try-catch
Validate before calling
// No data pre-check; this is a serializer fault. Confirm default ObjectMapper. return null;
Try / catch
try {
authz.policies().update(rep);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().equals("Failed to serialize clients")) {
log.error("Jackson could not serialize client id set {}", resolvedIds, e.getCause());
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- Failed to export user policy [{}]
- Failed to serialize client scopes
- Error while synchronizing clients with policy [{}].
- Could not parse clients [{}] from policy config [{}].
- Failed to export client scope policy [{}]
AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14).
Data as JSON: /api/errors/ff0b7ae0d64bd3b2.
Report an issue: GitHub.