spring-projects/spring-security · error · IOException
Failed to deserialize asserting party credential collection
Error message
Failed to deserialize asserting party credential collection
What it means
JdbcAssertingPartyMetadataRepository stores the asserting party's credential collection as a Java-serialized blob. deserialize() wraps ClassNotFoundException (a credential class missing on the classpath) into an IOException with this message, i.e. the stored blob references classes that cannot be loaded.
Solutions
- Align the application's Spring Security version with the one that wrote the rows, or re-write rows in the current format
- Prefer inserting credentials via the repository's modern column-based APIs instead of raw serialized blobs
- Inspect the cause ClassNotFoundException to find the missing class and add the dependency providing it
- Re-export metadata/credentials from the source environment into the target database
- Add the AllowlistObjectInputFilter-consistent classes to the classpath if a custom credential type was serialized
Example fix
// before: reading old serialized blobs across versions var creds = repository.findByEntityId(id); // IOException: ClassNotFoundException // after: re-write rows with current version, or run migration migrationRewriteCredentialBlobs(dataSource); var creds = repository.findByEntityId(id);
Defensive patterns
Strategy: try-catch
Try / catch
try {
var metadata = repository.findByEntityId(entityId);
} catch (DataAccessException | Saml2Exception ex) {
if (ex.getCause() instanceof IOException io && io.getCause() instanceof ClassNotFoundException cnf) {
logger.error("Serialized blob references missing class {} — re-write rows", cnf.getMessage());
}
throw ex;
} Prevention
- Never move serialized credential blobs across Spring Security versions — re-insert rows instead
- Pin the Spring Security version used by all services sharing the database
- Prefer the repository's typed setters over raw BLOB writes
When it happens
Trigger: Reading rows from the database whose credentials blob was written by a different Spring Security version or environment, and ObjectInputStream cannot resolve a class in the serialized credential graph.
Common situations: Spring Security upgraded/downgraded between write and read so serialized class signatures changed; reading a database written by a different application/JVM lacking saml classes; corrupted rows; restoring dumps across environments.
Related errors
- Failed to deserialize payload
- Unsupported element of type
- An error occurred reading the OpenID Client Registration
- An error occurred reading the OpenID Provider Configuration
- An error occurred while attempting to decode the Jwt
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/56046e0893aec7c7.
Report an issue: GitHub.
Appendix: source
Thrown at saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java:282
}
ALLOWLIST = new AllowlistObjectInputFilter(classes);
}
@Override
@SuppressWarnings("unchecked")
public Collection<Saml2X509Credential> deserialize(InputStream in) throws IOException {
ObjectInputStream oin = new ObjectInputStream(in);
oin.setObjectInputFilter(ALLOWLIST);
try {
Collection<Saml2X509Credential> credentials = (Collection<Saml2X509Credential>) oin.readObject();
for (Object credential : credentials) {
Assert.isInstanceOf(Saml2X509Credential.class, credential,
"Deserialized object is not of type Saml2X509Credential");
}
return credentials;
}
catch (ClassNotFoundException ex) {
throw new IOException("Failed to deserialize asserting party credential collection", ex);
}
}
private static final class AllowlistObjectInputFilter implements ObjectInputFilter {
private static final Log logger = LogFactory.getLog(JdbcAssertingPartyMetadataRepository.class);
private static final int MAX_DEPTH = 20;
private static final int MAX_REFS = 1000;
private static final int MAX_ARRAY = 16384;
private static final int MAX_BYTES = 1_048_576;
private final ObjectInputFilter delegate;
private AllowlistObjectInputFilter(Set<String> allowlist) {View on GitHub (pinned to 96852e8860)