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

  1. Inspect the wrapped IOException cause — it will reveal the Jackson-level failure.
  2. Remove or fix any custom JsonSerialization/ObjectMapper override.
  3. Retry the policy update; if it persists, isolate which client ID string (if any) breaks the mapper.
  4. 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

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


AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14). Data as JSON: /api/errors/ff0b7ae0d64bd3b2. Report an issue: GitHub.