{"record":{"id":"3da2afa3fe7de008","repo":"hibernate/hibernate-orm","slug":"tried-to-assemble-a-different-subclass-instance","errorCode":null,"errorMessage":"Tried to assemble a different subclass instance","messagePattern":"Tried to assemble a different subclass instance","errorType":"exception","errorClass":"AssertionFailure","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StandardCacheEntryImpl.java","lineNumber":135,"sourceCode":"\t * @param interceptor (currently unused)\n\t * @param session The session\n\t *\n\t * @return The assembled state\n\t *\n\t * @throws HibernateException Indicates a problem performing assembly or calling the PreLoadEventListeners.\n\t *\n\t * @see org.hibernate.type.Type#assemble\n\t * @see org.hibernate.type.Type#disassemble\n\t */\n\t@Nonnull\n\tpublic Object[] assemble(\n\t\t\t@Nonnull final Object instance,\n\t\t\t@Nonnull final Object id,\n\t\t\t@Nonnull final EntityPersister persister,\n\t\t\t@Nonnull final Interceptor interceptor,\n\t\t\t@Nonnull final SharedSessionContractImplementor session) throws HibernateException {\n\t\tif ( !persister.getEntityName().equals( subclass ) ) {\n\t\t\tthrow new AssertionFailure( \"Tried to assemble a different subclass instance\" );\n\t\t}\n\n\t\t// assembled state gets put in a new array (we read from cache by value!)\n\t\tfinal Object[] state = CacheEntryHelper.assemble(\n\t\t\t\tdisassembledState,\n\t\t\t\tpersister.getPropertyTypes(),\n\t\t\t\tsession, instance\n\t\t);\n\n\t\t//persister.setIdentifier(instance, id); //before calling interceptor, for consistency with normal load\n\n\t\tif ( session instanceof EventSource eventSource ) {\n\t\t\t//TODO: reuse the PreLoadEvent\n\t\t\tfinal PreLoadEvent preLoadEvent =\n\t\t\t\t\tnew PreLoadEvent( eventSource )\n\t\t\t\t\t\t\t.setEntity( instance )\n\t\t\t\t\t\t\t.setState( state )\n\t\t\t\t\t\t\t.setId( id )","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StandardCacheEntryImpl.java#L117-L153","documentation":"When Hibernate reassembles an entity from a second-level cache entry, StandardCacheEntryImpl.assemble verifies that the subclass name stored in the cache entry equals the entity name of the persister being loaded. A mismatch means the cache holds state written for a different class of the same inheritance hierarchy, breaking an internal invariant, so Hibernate throws AssertionFailure. In practice the cached entry is stale or was written by a different mapping version.","triggerScenarios":"Loading an entity from the L2 cache after its inheritance hierarchy, subclass names, or entity names changed while the cache survived (Ehcache disk store, Infinispan cluster across restarts); cluster nodes running different application versions against the same region; migrated or manually seeded cache data.","commonSituations":"Redeploying with renamed subclasses or changed discriminator mappings without clearing the second-level cache; rolling upgrades where old and new nodes share a clustered cache; local testing against a leftover cache directory from a previous build.","solutions":["Clear the affected cache region (or the whole cache) after changing entity inheritance mappings","Run identical mapping versions on all cluster nodes before they share cache regions","Start with a fresh cache store after redeployment (wipe the disk store or restart the cache cluster)","If it reproduces with consistent mappings and a clean cache, capture a minimal test case and report it to Hibernate (HHH)"],"exampleFix":"# before: redeploy with the old cache store in place\n# ./cache-store still holds entries from the previous mapping\n\n# after: evict on deploy\nsessionFactory.getCache().evictEntityRegions();\n# or wipe the provider store before boot: rm -rf ./cache-store","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return session.find(Order.class, id);\n} catch (AssertionFailure e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"different subclass\")) {\n        sessionFactory.getCache().evictEntityRegion(Order.class); // drop corrupt entry\n        return session.find(Order.class, id);                     // retry once from clean cache\n    }\n    throw e;\n}","preventionTips":["Evict second-level cache regions on every deploy that changes entity mappings","Version-stamp clustered caches and clear them during rolling upgrades","Treat AssertionFailure during cache assembly as corrupt cache data, not a broad catch target"],"tags":["hibernate","second-level-cache","inheritance","subclass","assertion"],"backgroundTag":"stale-second-level-cache","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}