hibernate/hibernate-orm · error · IllegalStateException

Assignment referred to columns from multiple tables

Error message

Assignment referred to columns from multiple tables

What it means

CteUpdateHandler buckets bulk-UPDATE assignments by table exactly like the insert handler: each single assignment's column references must resolve to ONE table of the mutated entity. When an assignment (typically an embedded/composite value or a split mapping) spans columns of two tables, this IllegalStateException aborts SQL generation. The source TODO notes the limitation could only be lifted by adding joins to DML statements.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteUpdateHandler.java:137

				updatingTableGroup.getTableReferenceJoins().size() + 1
		);

		for ( int i = 0; i < assignments.size(); i++ ) {
			final Assignment assignment = assignments.get( i );
			final List<ColumnReference> assignmentColumnRefs = assignment.getAssignable().getColumnReferences();

			TableReference assignmentTableReference = null;

			for ( int c = 0; c < assignmentColumnRefs.size(); c++ ) {
				final ColumnReference columnReference = assignmentColumnRefs.get( c );
				final TableReference tableReference = resolveTableReference(
						columnReference,
						tableReferenceByAlias
				);

				// TODO: this could be fixed by introducing joins to DML statements
				if ( assignmentTableReference != null && !assignmentTableReference.equals( tableReference ) ) {
					throw new IllegalStateException( "Assignment referred to columns from multiple tables" );
				}

				assignmentTableReference = tableReference;
			}
			assert assignmentTableReference != null;

			List<Assignment> assignmentsForTable = assignmentsByTable.get( assignmentTableReference );
			if ( assignmentsForTable == null ) {
				assignmentsForTable = new ArrayList<>();
				assignmentsByTable.put( assignmentTableReference, assignmentsForTable );
			}
			assignmentsForTable.add( assignment );
		}

		// For nullable tables we have to also generate an insert CTE
		for (int i = 0; i < entityPersister.getTableSpan(); i++) {
			if ( entityPersister.isNullableTable( i ) ) {
				final String tableExpression = entityPersister.getTableName( i );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Set the scalar attributes individually so each assignment lands in one table: `set p.details.a = :a, p.details.b = :b` grouped so components stay single-table
  2. Rework the mapping so each embedded/attribute maps to one table only
  3. Remove the forced CTE mutation strategy to fall back to the table-based handler
  4. Upgrade to the newest 6.x patch and check Hibernate JIRA; file a reproducer if the mapping is legitimate

Example fix

// before
update Person p set p.details = :details

// after (details split per table)
update Person p set p.mainDetails = :main, p.extraDetails = :extra
Defensive patterns

Strategy: try-catch

Validate before calling

// Before bulk-updating an embeddable, confirm all its columns share one table
// (check @AttributeOverride/@Table mappings); otherwise set members individually
if (assignmentIsEmbeddable(setPath)) {
    assertEmbeddableSingleTable(entityMeta, setPath);
}

Try / catch

try {
    em.createQuery(updateHql).executeUpdate();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("multiple tables")) {
        throw new MappingIssueException(
            "One SET assignment spans two tables — split it per table or per attribute", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: `update Person p set p.details = :d` where the Details embeddable maps columns into both the primary table and a @SecondaryTable; SET clauses whose assignable spans formula columns across tables; bulk updates on joined-inheritance entities with cross-table components, executed via CteMutationStrategy.

Common situations: @SecondaryTable modeling where an embeddable straddles tables; switching mutation strategy to CTE on PostgreSQL and suddenly hitting this on previously-working bulk updates; Hibernate 6.x regressions around secondary-table bulk updates.

Related errors


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