hibernate/hibernate-orm · error · IllegalArgumentException

Cross join treats can not be fetched

Error message

Cross join treats can not be fetched

What it means

Fetching through a treat is only meaningful for association fetches. SqmCrossJoin.treatAs(..., alias, fetch) throws IllegalArgumentException('Cross join treats can not be fetched') when fetch=true - a cross join is not a fetch point, so Hibernate rejects the request outright (and the Class convenience overload always passes fetch=false).

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/from/SqmCrossJoin.java:211

	@Nonnull
	public <S extends T> SqmTreatedCrossJoin<L, T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias) {
		return treatAs( treatTarget, alias, false );
	}

	@Override
	@Nonnull
	public <S extends T> SqmTreatedCrossJoin<L, T, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias, boolean fetch) {
		return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, false );
	}

	@Override
	@Nonnull
	public <S extends T> SqmTreatedCrossJoin<L, T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias, boolean fetch) {
		if ( alias != null ) {
			throw new IllegalArgumentException( "Cross join treats can not be aliased" );
		}
		if ( fetch ) {
			throw new IllegalArgumentException( "Cross join treats can not be fetched" );
		}
		final var treat = (SqmTreatedCrossJoin<L, T, S>) findTreat( treatTarget, null );
		if ( treat == null ) {
			return addTreat( new SqmTreatedCrossJoin<>( this, (SqmEntityDomainType<S>) treatTarget ) );
		}
		else {
			return treat;
		}
	}

	@Nonnull
	@Override
	public <S extends T> SqmTreatedCrossJoin<L, T, S> treatAs(@Nonnull Class<S> treatAsType) {
		return treatAs( treatAsType, null, false );
	}

	@Nonnull
	@Override

View on GitHub (pinned to fad1729dce)

Solutions

  1. Call the fetch-less overload: crossJoin.treatAs(Sub.class).
  2. Add a real fetch join for the subtype attribute you need instead of fetching through a cross-join treat.
  3. In generic code, force fetch=false when the join is an SqmCrossJoin.

Example fix

// before
crossJoin.treatAs( Sub.class, null, true ); // IllegalArgumentException

// after
crossJoin.treatAs( Sub.class );             // fetch=false by default
// fetch subtype state via an explicit fetch join instead
Defensive patterns

Strategy: validation

Validate before calling

static boolean treatSupportsFetch(SqmJoin<?, ?> join) {
    return !( join instanceof SqmCrossJoin );
}
// usage:
join.treatAs( Sub.class, null, treatSupportsFetch( join ) && wantFetch );

Prevention

When it happens

Trigger: Calling crossJoin.treatAs(Sub.class, null, true) or any convenience overload that requests fetch: generic fetch-treat helpers applied to all joins, or code that always passes fetch=true to avoid lazy subtype state.

Common situations: Generic treat/fetch utilities that do not branch on join type; porting fetch-treat usage from explicit joins to cross joins; performance tuning that blindly fetches through treats.

Related errors


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