hibernate/hibernate-orm · error · IllegalArgumentException

Join type has no JPA join type mapping: {}

Error message

Join type has no JPA join type mapping: {}

What it means

SqmJoinType.getCorrespondingJpaJoinType() maps the SQM join kinds to jakarta.persistence.criteria.JoinType. RIGHT, LEFT, INNER and FULL have explicit mappings; SqmJoinType.CROSS has none and falls into the default branch, throwing IllegalArgumentException. So converting a cross join (created via crossJoin(...), see SqmCrossJoin.getSqmJoinType() == CROSS) to a JPA criteria join type always fails.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/SqmJoinType.java:75

	}

	public SqlAstJoinType getCorrespondingSqlJoinType() {
		return switch (this) {
			case RIGHT -> SqlAstJoinType.RIGHT;
			case LEFT -> SqlAstJoinType.LEFT;
			case INNER -> SqlAstJoinType.INNER;
			case FULL -> SqlAstJoinType.FULL;
			case CROSS -> SqlAstJoinType.CROSS;
		};
	}

	public jakarta.persistence.criteria.JoinType getCorrespondingJpaJoinType() {
		return switch (this) {
			case RIGHT -> jakarta.persistence.criteria.JoinType.RIGHT;
			case LEFT -> jakarta.persistence.criteria.JoinType.LEFT;
			case INNER -> jakarta.persistence.criteria.JoinType.INNER;
			case FULL -> jakarta.persistence.criteria.JoinType.FULL;
			default -> throw new IllegalArgumentException( "Join type has no JPA join type mapping: " + this );
		};
	}

	public JoinType getCorrespondingJoinType() {
		return switch (this) {
			case RIGHT -> JoinType.RIGHT;
			case LEFT -> JoinType.LEFT;
			case INNER -> JoinType.INNER;
			case FULL -> JoinType.FULL;
			case CROSS -> JoinType.CROSS;
		};
	}

	public static SqmJoinType from(JoinType joinType) {
		return switch ( joinType ) {
			case INNER -> INNER;
			case LEFT -> LEFT;
			case RIGHT -> RIGHT;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Special-case CROSS before converting: render it as a plain inner join (cross join semantics) or handle it separately.
  2. Use getCorrespondingJoinType() (org.hibernate.query.JoinType) instead, which supports CROSS.
  3. Replace crossJoin(Class) with a regular join to an entity and an explicit join predicate when downstream code needs JPA join types.

Example fix

// before
jakarta.persistence.criteria.JoinType jt = sqmJoin.getSqmJoinType().getCorrespondingJpaJoinType(); // throws for CROSS
// after
jakarta.persistence.criteria.JoinType jt = sqmJoin.getSqmJoinType() == SqmJoinType.CROSS
        ? jakarta.persistence.criteria.JoinType.INNER
        : sqmJoin.getSqmJoinType().getCorrespondingJpaJoinType();
Defensive patterns

Strategy: type-guard

Type guard

static Optional<jakarta.persistence.criteria.JoinType> toJpaJoinType(SqmJoinType t) {
    return t == SqmJoinType.CROSS
        ? Optional.empty() // no JPA counterpart
        : Optional.of( t.getCorrespondingJpaJoinType() );
}

Prevention

When it happens

Trigger: Calling SqmJoinType.CROSS.getCorrespondingJpaJoinType() directly, or SQM-processing code (custom walkers, criteria copiers, renderers) doing sqmJoin.getSqmJoinType().getCorrespondingJpaJoinType() on a SqmCrossJoin or any join whose type is CROSS.

Common situations: Frameworks/tools that mirror an SQM tree into a jakarta criteria tree; adding crossJoin() to a query that such a tool then visits; upgrading code that previously only saw LEFT/INNER joins.

Related errors


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