hibernate/hibernate-orm · error · AssertionFailure

Tried to assemble a different subclass instance

Error message

Tried to assemble a different subclass instance

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/cache/spi/entry/StandardCacheEntryImpl.java:135

	 * @param interceptor (currently unused)
	 * @param session The session
	 *
	 * @return The assembled state
	 *
	 * @throws HibernateException Indicates a problem performing assembly or calling the PreLoadEventListeners.
	 *
	 * @see org.hibernate.type.Type#assemble
	 * @see org.hibernate.type.Type#disassemble
	 */
	@Nonnull
	public Object[] assemble(
			@Nonnull final Object instance,
			@Nonnull final Object id,
			@Nonnull final EntityPersister persister,
			@Nonnull final Interceptor interceptor,
			@Nonnull final SharedSessionContractImplementor session) throws HibernateException {
		if ( !persister.getEntityName().equals( subclass ) ) {
			throw new AssertionFailure( "Tried to assemble a different subclass instance" );
		}

		// assembled state gets put in a new array (we read from cache by value!)
		final Object[] state = CacheEntryHelper.assemble(
				disassembledState,
				persister.getPropertyTypes(),
				session, instance
		);

		//persister.setIdentifier(instance, id); //before calling interceptor, for consistency with normal load

		if ( session instanceof EventSource eventSource ) {
			//TODO: reuse the PreLoadEvent
			final PreLoadEvent preLoadEvent =
					new PreLoadEvent( eventSource )
							.setEntity( instance )
							.setState( state )
							.setId( id )

View on GitHub (pinned to fad1729dce)

Solutions

  1. Clear the affected cache region (or the whole cache) after changing entity inheritance mappings
  2. Run identical mapping versions on all cluster nodes before they share cache regions
  3. Start with a fresh cache store after redeployment (wipe the disk store or restart the cache cluster)
  4. If it reproduces with consistent mappings and a clean cache, capture a minimal test case and report it to Hibernate (HHH)

Example fix

# before: redeploy with the old cache store in place
# ./cache-store still holds entries from the previous mapping

# after: evict on deploy
sessionFactory.getCache().evictEntityRegions();
# or wipe the provider store before boot: rm -rf ./cache-store
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return session.find(Order.class, id);
} catch (AssertionFailure e) {
    if (e.getMessage() != null && e.getMessage().contains("different subclass")) {
        sessionFactory.getCache().evictEntityRegion(Order.class); // drop corrupt entry
        return session.find(Order.class, id);                     // retry once from clean cache
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/3da2afa3fe7de008. Report an issue: GitHub.