hibernate/hibernate-orm · error · UnsupportedOperationException

Treated cross joins doesn't support explicit alias

Error message

Treated cross joins doesn't support explicit alias

What it means

A treated cross join wraps an SqmCrossJoin (an entity name referenced directly in FROM, or a criteria cross join) under TREAT. The wrapper intentionally rejects setExplicitAlias because aliasing is owned by the underlying cross join node — assigning a second alias to the treat result would corrupt the FROM clause — so it throws UnsupportedOperationException('Treated cross joins doesn't support explicit alias').

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmTreatedCrossJoin.java:80

		final var existing = context.getCopy( this );
		if ( existing != null ) {
			return existing;
		}
		final var path = context.registerCopy(
				this,
				new SqmTreatedCrossJoin<>(
						getNavigablePath(),
						wrappedPath.copy( context ),
						treatTarget
				)
		);
		copyTo( path, context );
		return path;
	}

	@Override
	public void setExplicitAlias(@Nullable String explicitAlias) {
		throw new UnsupportedOperationException("Treated cross joins doesn't support explicit alias");
	}

	@Nonnull
	@Override
	public SqmEntityDomainType<S> getTreatTarget() {
		return treatTarget;
	}

	@Nonnull
	@Override
	public SqmEntityDomainType<S> getModel() {
		return treatTarget;
	}

	@Override
	public SqmCrossJoin<L, T> getWrappedPath() {
		return wrappedPath;
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Set the alias on the underlying cross join before treating: root.alias("b") then root.treatAs(Book.class), and reference the treated node without its own alias.
  2. Restructure the query as an association join (root.join("books")) with treat, which supports aliases normally.
  3. If the alias is only needed for ordering/selection references, reference the original root's alias instead.
  4. Check newer Hibernate 6.x releases — treat alias handling has been progressively improved; upgrade if the query shape is valid HQL.

Example fix

// before
JpaFrom<?, Product> treated = ((JpaFrom<?, Product>) root).treatAs(Book.class);
treated.alias("b"); // UnsupportedOperationException
// after
root.alias("b"); // alias the underlying from-element first
JpaFrom<?, Book> treated = ((JpaFrom<?, Product>) root).treatAs(Book.class);
query.where(cb.equal(treated.get("isbn"), "...")); // reference without its own alias
Defensive patterns

Strategy: validation

Validate before calling

// Apply aliases only to from-elements that accept them; alias the source BEFORE treating
JpaFrom<?, Product> src = (JpaFrom<?, Product>) root.alias("b");
JpaFrom<?, Book> treated = src.treatAs(Book.class);
// do NOT call treated.alias(...) on a treated cross join

Type guard

static boolean aliasable(Selection<?> sel) {
    return !(sel instanceof SqmTreatedCrossJoin); // treated cross joins reject explicit aliases
}

Try / catch

try {
    selection.alias(alias);
} catch (UnsupportedOperationException e) {
    // treated cross join: alias was already set on the wrapped join; skip
}

Prevention

When it happens

Trigger: Calling .alias(...) (JPA Selection.alias) or otherwise setting an explicit alias on the node returned by crossJoinRoot.treatAs(Sub.class) in the criteria API; HQL constructs that bind an alias token to a treated entity-name from-element.

Common situations: Criteria queries that cross-join an entity and immediately TREAT it, then try to alias the treated node; code generators that call alias() on every selection; mixing root.alias() and treated.alias() in the same query.

Related errors


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