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
SqmDerivedJoin models `join (subquery) alias` (criteria `JpaFrom.join(Subquery)` / `joinLateral(Subquery, JoinType)`). When lateral=true the subquery may reference preceding FROM items, which by SQL semantics requires the referenced side to come first — so only LEFT and INNER joins are meaningful for a lateral join. The private static validateJoinType(SqmJoinType, boolean lateral) helper enforces this in the constructor and throws IllegalArgumentException for RIGHT/FULL/CROSS the instant the join node is created (parse/build time, never execution time).
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/from/SqmDerivedJoin.java:88
navigablePath,
pathSource,
sqmRoot,
alias,
joinType,
sqmRoot.nodeBuilder()
);
this.subQuery = subQuery;
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 SqmDerivedJoin<T> copy(SqmCopyContext context) {
final var existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
//noinspection unchecked
final var path = context.registerCopy(View on GitHub (pinned to fad1729dce)
Solutions
- Switch to `left join lateral` or plain `join lateral` (SqmJoinType.LEFT / INNER) — these are the only legal lateral join types.
- For RIGHT semantics, invert the query: put the referenced entity first in FROM and keep the lateral subquery on its right with LEFT/INNER.
- For FULL OUTER semantics, emulate with a UNION of two directional queries, or correlate via a non-lateral subquery in the WHERE clause.
Example fix
// before - IllegalArgumentException: Lateral joins can only be left or inner JpaDerivedJoin<LineItem> items = order.joinLateral( itemsSub, JoinType.RIGHT ); // after - referenced root stays on the left; lateral join uses LEFT (or INNER) JpaDerivedJoin<LineItem> items = order.joinLateral( itemsSub, JoinType.LEFT ); /* HQL equivalent: before: select o.id, i.name from Order o right join lateral (select i from LineItem i where i.order = o) i on true after: select o.id, i.name from Order o left join lateral (select i from LineItem i where i.order = o) i */
Defensive patterns
Strategy: validation
Validate before calling
// validate before constructing the lateral join
import org.hibernate.query.common.JoinType;
static JoinType requireLateralJoinType(JoinType requested) {
if ( requested != JoinType.LEFT && requested != JoinType.INNER ) {
throw new IllegalArgumentException(
"Lateral derived joins support only LEFT/INNER, got " + requested
+ "; reorder the FROM clause instead" );
}
return requested;
}
// then
JpaDerivedJoin<X> dj = root.joinLateral( sub, requireLateralJoinType( joinType ) ); Type guard
import org.hibernate.query.sqm.tree.SqmJoinType;
static boolean isLateralLegal(SqmJoinType t) {
return t == SqmJoinType.LEFT || t == SqmJoinType.INNER;
} Try / catch
try {
return from.joinLateral( subquery, requestedType );
} catch ( IllegalArgumentException e ) {
if ( String.valueOf( e.getMessage() ).startsWith( "Lateral joins" ) ) {
// construction-time query-shape bug: fail with context, do not retry blindly
throw new QueryConstructionException(
"Only LEFT/INNER lateral joins are legal; requested " + requestedType, e );
}
throw e;
} Prevention
- Restrict lateral joins to LEFT and INNER — RIGHT/FULL/CROSS lateral has no SQL meaning because the lateral input depends on preceding FROM items.
- To invert direction, reorder the FROM clause so the referenced table precedes the lateral subquery.
- Validate the join type once in your query-DSL layer before calling joinLateral/join(subquery, type, true).
- Smoke-test generated SQL per dialect: lateral support varies and some dialects emulate it.
When it happens
Trigger: Building a lateral derived join with an illegal type: criteria `root.joinLateral(subquery, org.hibernate.query.common.JoinType.RIGHT)` or `root.join(subquery, JoinType.FULL, true)`; HQL `right join lateral (select ...) d on ...` or `full join lateral (select ...) d on ...`.
Common situations: Porting correlated RIGHT/FULL outer subquery joins from native SQL to HQL/criteria; dynamic query builders that pass a user-supplied join type straight into joinLateral; developers assuming any join type composes with LATERAL because the database accepts it in hand-written SQL.
Related errors
- Lateral joins can only be left or inner. Illegal join type:
- Derived joins can not be treated
- CTE joins can not be treated
- Entity join treats can not be aliased
- Function joins can not be treated
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/6450aadb83f73bc0.
Report an issue: GitHub.