hibernate/hibernate-orm · error · IllegalArgumentException
Lateral joins can only be left or inner. Illegal join type:
Error message
Lateral joins can only be left or inner. Illegal join type: " + joinType
What it means
SqmFunctionJoin models a join to a set-returning function result (HQL `join unnest(:ids) i`, `join generate_series(1,10) g`; criteria `JpaFrom.join(JpaSetReturningFunction, SqmJoinType[, boolean lateral])`). When lateral=true, the function input may reference preceding FROM items, so only LEFT and INNER joins have SQL meaning. The static validateJoinType(SqmJoinType, boolean lateral) helper in this constructor throws IllegalArgumentException for RIGHT/FULL/CROSS as soon as the join node is created — at query-build time, never at execution time.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/from/SqmFunctionJoin.java:87
navigablePath,
pathSource,
sqmFrom,
alias,
joinType,
sqmFrom.nodeBuilder()
);
this.function = function;
this.lateral = lateral;
}
private static SqmJoinType validateJoinType(SqmJoinType joinType, boolean lateral) {
if ( lateral ) {
switch ( joinType ) {
case LEFT:
case INNER:
break;
default:
throw new IllegalArgumentException( "Lateral joins can only be left or inner. Illegal join type: " + joinType );
}
}
return joinType;
}
@Override
public boolean isImplicitlySelectable() {
return false;
}
@Override
public SqmFunctionJoin<E> copy(SqmCopyContext context) {
final var existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final var path = context.registerCopy(
this,View on GitHub (pinned to fad1729dce)
Solutions
- Use `left join lateral` or `join lateral` (SqmJoinType.LEFT/INNER) — the only legal types for lateral function joins.
- For RIGHT semantics, reorder FROM so the referenced entity precedes the function join and keep the function join LEFT/INNER.
- For FULL OUTER semantics, emulate with UNION of two directional queries or move the correlation into the WHERE clause without LATERAL.
Example fix
// before - IllegalArgumentException: Lateral joins can only be left or inner JpaFunctionJoin<Long> g = root.joinLateral( cb.generateSeries( 1, 10 ), SqmJoinType.RIGHT ); // after - LEFT (or INNER) lateral function join JpaFunctionJoin<Long> g = root.joinLateral( cb.generateSeries( 1, 10 ), SqmJoinType.LEFT ); -- HQL equivalent -- before: select p, i from Person p right join lateral unnest(p.friendIds) i -- after: select p, i from Person p left join lateral unnest(p.friendIds) i
Defensive patterns
Strategy: validation
Validate before calling
// validate the join type before building the lateral function join
import org.hibernate.query.sqm.tree.SqmJoinType;
static SqmJoinType requireLateral(SqmJoinType requested) {
if ( requested != SqmJoinType.LEFT && requested != SqmJoinType.INNER ) {
throw new IllegalArgumentException(
"Lateral function joins support only LEFT/INNER, got " + requested );
}
return requested;
}
// then
JpaFunctionJoin<X> fj = root.joinLateral( setReturningFunction, requireLateral( joinType ) ); Type guard
static boolean isLateralLegal(org.hibernate.query.sqm.tree.SqmJoinType t) {
return t == org.hibernate.query.sqm.tree.SqmJoinType.LEFT
|| t == org.hibernate.query.sqm.tree.SqmJoinType.INNER;
} Try / catch
try {
return from.joinLateral( function, sqmJoinType );
} catch ( IllegalArgumentException e ) {
if ( String.valueOf( e.getMessage() ).startsWith( "Lateral joins" ) ) {
throw new QueryConstructionException(
"Only LEFT/INNER lateral function joins are legal; got " + sqmJoinType, e );
}
throw e;
} Prevention
- Only LEFT/INNER for lateral function joins (unnest, generate_series, table functions) — the lateral input depends on preceding FROM items.
- Invert direction by reordering FROM: referenced entity first, function join after.
- Clamp or validate user-supplied join types in your query API before passing them to joinLateral.
- Verify dialect support: lateral function joins may compile to different SQL per database.
When it happens
Trigger: Criteria `root.joinLateral(setReturningFunction, SqmJoinType.RIGHT)` or `root.join(function, SqmJoinType.FULL, true)`; HQL `right join lateral unnest(:ids) i` or `full join lateral generate_series(1,10) g on ...`.
Common situations: Porting native lateral/right-join-function SQL (PostgreSQL lateral unnest) to HQL; dynamic join builders forwarding a user-chosen join type into join(function, type, lateral); assuming LATERAL composes with every join type because the raw SQL engine is permissive.
Related errors
- Lateral joins can only be left or inner. Illegal join type:
- Function joins can not be treated
- CTE joins can not be treated
- Derived joins can not be treated
- Entity join treats can not be aliased
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/b1dcc985179e377a.
Report an issue: GitHub.