hibernate/hibernate-orm · error · UnsupportedOperationException

Can't emulate '" + tableJoin.getJoinType().getText() + "join

Error message

Can't emulate '" + tableJoin.getJoinType().getText() + "join' in a DB2 recursive query part

What it means

NamedTableReference is the from-element for one concrete named table; resolveTableReference returns itself only when the requested expression equals its own tableExpression and throws UnknownTableReferenceException otherwise. Hitting it means the resolver asked a single-table reference for a different table's name - usually a secondary or subclass table being resolved against the primary table reference instead of the enclosing table group.

Source

Thrown at hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java:93

	}

	@Override
	protected void renderTableReferenceJoins(TableGroup tableGroup, LockMode lockMode, int swappedJoinIndex, boolean forceLeftJoin) {
		// When we are in a recursive CTE, we can't render joins on DB2...
		// See https://modern-sql.com/feature/with-recursive/db2/error-345-state-42836
		if ( isInRecursiveQueryPart() ) {
			final List<TableReferenceJoin> joins = tableGroup.getTableReferenceJoins();
			if ( joins == null || joins.isEmpty() ) {
				return;
			}

			for ( TableReferenceJoin tableJoin : joins ) {
				switch ( tableJoin.getJoinType() ) {
					case CROSS:
					case INNER:
						break;
					default:
						throw new UnsupportedOperationException( "Can't emulate '" + tableJoin.getJoinType().getText() + "join' in a DB2 recursive query part" );
				}
				appendSql( COMMA_SEPARATOR_CHAR );

				renderNamedTableReference( tableJoin.getJoinedTableReference(), LockMode.NONE );

				if ( tableJoin.getPredicate() != null && !tableJoin.getPredicate().isEmpty() ) {
					addAdditionalWherePredicate( tableJoin.getPredicate() );
				}
			}
		}
		else {
			super.renderTableReferenceJoins( tableGroup, lockMode, swappedJoinIndex, forceLeftJoin );
		}
	}

	@Override
	protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {
		if ( isInRecursiveQueryPart() ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Resolve through the TableGroup (group.resolveTableReference(...)) rather than a single NamedTableReference when secondary/subclass tables may be involved.
  2. Verify the attribute's mapped table matches the mapping (column listed under the right table/@SecondaryTable) after schema refactors.
  3. Ensure secondary-table joins are not pruned when their columns are selected.
  4. Upgrade Hibernate; report if core code resolves at the wrong level.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return query.getResultList();
} catch ( UnknownTableReferenceException e ) {
    // secondary/subclass table resolved against the primary reference: fix the mapping or query the right group
    LOG.error("Table {} not on primary reference - check @SecondaryTable mapping for {}", e.getTableExpression(), entity);
    throw e;
}

Prevention

When it happens

Trigger: Resolving a secondary-table column (@SecondaryTable/@SecondaryTables) or a subclass table directly on the primary NamedTableReference instead of through the TableGroup; join pruning or custom translators resolving columns at reference level; mapping changes where a column's table no longer matches the reference.

Common situations: Entities with secondary tables after remapping columns between primary and secondary; custom SqlAstTranslator extensions resolving columns via table references; upgrades tightening reference-level vs group-level resolution.

Related errors


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