hibernate/hibernate-orm · error · IllegalStateException

Encountered 'subclass table index' [%s] was outside expected

Error message

Encountered 'subclass table index' [%s] was outside expected range ( [%s] < i < [%s] )

What it means

Thrown while Hibernate builds the persister for a JOINED inheritance hierarchy. associateSubclassNamesToSubclassTableIndex maps each subclass-owned table to a slot in subclassNamesBySubclassTable; the computed index (position in subclassTableNameClosure minus coreTableSpan) must fall within [0, mapping.length). This error means the resolved index fell outside that array, i.e. a table owned by a subclass collided with the core (root/superclass) tables or the table-span arithmetic is inconsistent. It is an internal mapping invariant violation that aborts SessionFactory construction.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java:617

		associateSubclassNamesToSubclassTableIndex( tableName, classNames, mapping );
		for ( var join : persistentClass.getJoins() ) {
			final String secondaryTableName = join.getTable().getQualifiedName( context );
			associateSubclassNamesToSubclassTableIndex( secondaryTableName, classNames, mapping );
		}
	}

	private void associateSubclassNamesToSubclassTableIndex(
			String tableName,
			Set<String> classNames,
			String[][] mapping) {
		// find the table's entry in the subclassTableNameClosure array
		boolean found = false;
		for ( int i = 1; i < subclassTableNameClosure.length; i++ ) {
			if ( subclassTableNameClosure[i].equals( tableName ) ) {
				found = true;
				final int index = i - coreTableSpan;
				if ( index < 0 || index >= mapping.length ) {
					throw new IllegalStateException(
							String.format(
									"Encountered 'subclass table index' [%s] was outside expected range ( [%s] < i < [%s] )",
									index,
									0,
									mapping.length
							)
					);
				}
				mapping[index] = toStringArray( classNames );
				break;
			}
		}
		if ( !found ) {
			throw new IllegalStateException(
					String.format(
							"Was unable to locate subclass table [%s] in 'subclassTableNameClosure'",
							tableName
					)

View on GitHub (pinned to fad1729dce)

Solutions

  1. Make every table name in the JOINED hierarchy unique, including secondary tables and @JoinTable names
  2. Check @SecondaryTable/@Table/@JoinTable name collisions between root, superclass joins, and subclass joins (case-insensitive compare)
  3. Upgrade to the latest Hibernate patch release - invariant bugs around subclass table closure have been fixed across 6.x/7.x
  4. Reduce the mapping to a minimal reproducer and report it as a Hibernate (HHH) issue with the mapping

Example fix

// before: subclass join reuses the root table name
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person { ... }

@Entity
@SecondaryTable(name = "person") // same as root table -> index collapses
public class Customer extends Person { ... }

// after: unique table name
@Entity
@SecondaryTable(name = "customer_details")
public class Customer extends Person { ... }
Defensive patterns

Strategy: validation

Validate before calling

// after building Metadata, before SessionFactory: no duplicate table names per hierarchy
for (PersistentClass pc : metadata.getEntityBindings()) {
    Set<String> names = new HashSet<>();
    names.add(pc.getRootTable().getName().toLowerCase(Locale.ROOT));
    pc.getJoinClosureIterator().forEachRemaining(j -> {
        if (!names.add(j.getTable().getName().toLowerCase(Locale.ROOT))) {
            throw new IllegalStateException("Duplicate table name in hierarchy of " + pc.getEntityName());
        }
    });
}

Try / catch

try { sessionFactory = metadata.buildSessionFactory(); } catch (IllegalStateException e) { /* mapping invariant failure: fix hierarchy table names, fail fast in CI */ throw e; }

Prevention

When it happens

Trigger: SessionFactory boot with @Inheritance(JOINED) where a subclass table, secondary table, or @JoinTable reuses the name of the root table or a core superclass table; hbm.xml <join> mappings with duplicate table names across the hierarchy; rarely an internal Hibernate defect in coreTableSpan computation.

Common situations: Copy-pasted @Table(name=...) values across a hierarchy; @SecondaryTable/@JoinTable names colliding with core tables; migrating hbm.xml joins from Hibernate 5; upgrading between 6.x/7.x versions and hitting an edge case in subclass table closure construction.

Related errors


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