{"record":{"id":"56046e0893aec7c7","repo":"spring-projects/spring-security","slug":"failed-to-deserialize-asserting-party-credential-c","errorCode":null,"errorMessage":"Failed to deserialize asserting party credential collection","messagePattern":"Failed to deserialize asserting party credential collection","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java","lineNumber":282,"sourceCode":"\t\t\t\t}\n\t\t\t\tALLOWLIST = new AllowlistObjectInputFilter(classes);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tpublic Collection<Saml2X509Credential> deserialize(InputStream in) throws IOException {\n\t\t\t\tObjectInputStream oin = new ObjectInputStream(in);\n\t\t\t\toin.setObjectInputFilter(ALLOWLIST);\n\t\t\t\ttry {\n\t\t\t\t\tCollection<Saml2X509Credential> credentials = (Collection<Saml2X509Credential>) oin.readObject();\n\t\t\t\t\tfor (Object credential : credentials) {\n\t\t\t\t\t\tAssert.isInstanceOf(Saml2X509Credential.class, credential,\n\t\t\t\t\t\t\t\t\"Deserialized object is not of type Saml2X509Credential\");\n\t\t\t\t\t}\n\t\t\t\t\treturn credentials;\n\t\t\t\t}\n\t\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t\tthrow new IOException(\"Failed to deserialize asserting party credential collection\", ex);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate static final class AllowlistObjectInputFilter implements ObjectInputFilter {\n\n\t\t\t\tprivate static final Log logger = LogFactory.getLog(JdbcAssertingPartyMetadataRepository.class);\n\n\t\t\t\tprivate static final int MAX_DEPTH = 20;\n\n\t\t\t\tprivate static final int MAX_REFS = 1000;\n\n\t\t\t\tprivate static final int MAX_ARRAY = 16384;\n\n\t\t\t\tprivate static final int MAX_BYTES = 1_048_576;\n\n\t\t\t\tprivate final ObjectInputFilter delegate;\n\n\t\t\t\tprivate AllowlistObjectInputFilter(Set<String> allowlist) {","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/JdbcAssertingPartyMetadataRepository.java#L264-L300","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: reading old serialized blobs across versions\nvar creds = repository.findByEntityId(id); // IOException: ClassNotFoundException\n// after: re-write rows with current version, or run migration\nmigrationRewriteCredentialBlobs(dataSource);\nvar creds = repository.findByEntityId(id);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    var metadata = repository.findByEntityId(entityId);\n} catch (DataAccessException | Saml2Exception ex) {\n    if (ex.getCause() instanceof IOException io && io.getCause() instanceof ClassNotFoundException cnf) {\n        logger.error(\"Serialized blob references missing class {} — re-write rows\", cnf.getMessage());\n    }\n    throw ex;\n}","preventionTips":["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"],"tags":["saml","jdbc","deserialization","classpath"],"backgroundTag":"class-not-found","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}