hibernate/hibernate-orm · error · SemanticException

Unmapped polymorphic reference cannot be used as a target of

Error message

Unmapped polymorphic reference cannot be used as a target of 'cross join'

What it means

consumeCrossJoin resolves the 'cross join' target entity name and rejects SqmPolymorphicRootDescriptor targets: an unmapped polymorphic reference has no single table set to cross join against, so Hibernate throws SemanticException rather than expanding the polymorphism.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java:2256

		return extractAlias( ctx );
	}

	protected String extractAlias(HqlParser.VariableContext ctx) {
		return SqmTreeCreationHelper.extractAlias( ctx, this );
	}

	@Override
	public final SqmCrossJoin<?, ?> visitCrossJoin(HqlParser.CrossJoinContext ctx) {
		throw new UnsupportedOperationException( "Unexpected call to #visitCrossJoin, see #consumeCrossJoin" );
	}

	protected <T> void consumeCrossJoin(HqlParser.CrossJoinContext parserJoin, SqmRoot<T> sqmRoot) {
		final String name = getEntityName( parserJoin.entityName() );

		final var entityDescriptor = getJpaMetamodel().resolveHqlEntityReference( name );

		if ( entityDescriptor instanceof SqmPolymorphicRootDescriptor ) {
			throw new SemanticException( "Unmapped polymorphic reference cannot be used as a target of 'cross join'",
					query );
		}
		final var join = new SqmCrossJoin<>(
				(SqmEntityDomainType<T>) entityDescriptor,
				extractAlias( parserJoin.variable() ),
				sqmRoot
		);

		processingStateStack.getCurrent().getPathRegistry().register( join );

		// CROSS joins are always added to the root
		sqmRoot.addSqmJoin( join );
	}

	private JpaMetamodel getJpaMetamodel() {
		return getCreationContext().getJpaMetamodel();
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Cross join a concrete mapped entity instead of the polymorphic reference
  2. If polymorphic behavior is needed, query the polymorphic root at top level and join associations explicitly
  3. Validate user-supplied join targets against the metamodel before building the HQL

Example fix

// before
select e, o from Employee e cross join java.lang.Object o

// after
select e, d from Employee e cross join Department d
Defensive patterns

Strategy: validation

Validate before calling

static boolean crossJoinTargetIsConcrete(EntityManagerFactory emf, String name) {
    return emf.getMetamodel().getEntities().stream().anyMatch(e -> e.getName().equals(name));
}
// reject cross join targets that are namespace/polymorphic names before building HQL
if (!crossJoinTargetIsConcrete(emf, joinTarget)) throw new IllegalArgumentException("Cross join target must be a concrete entity: " + joinTarget);

Try / catch

try {
    return em.createQuery(hql, Object[].class).getResultList();
} catch (org.hibernate.query.sqm.SemanticException e) {
    if (e.getMessage() != null && e.getMessage().contains("'cross join'")) {
        throw new IllegalArgumentException("Replace the polymorphic cross join target with a concrete entity", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: 'from Employee e cross join java.lang.Object o'; 'cross join' against a package-namespace polymorphic name that resolves to multiple entities.

Common situations: Migrating native cross joins over broad type sets into HQL; generic query builders joining whatever name the user supplies without validating it maps to one entity.

Related errors


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