hibernate/hibernate-orm · error · IllegalArgumentException

Passed attribute [%s] did not correspond to a joinable refer

Error message

Passed attribute [%s] did not correspond to a joinable reference [%s] relative to %s

What it means

The generic attribute-join builder in AbstractSqmFrom dispatches on the kind of the resolved path source: SqmSingularJoin for singular (association/embedded) attributes and bag/list/map/set builders for the plural kinds. Anything else, i.e. a basic-typed attribute such as a String or Integer column, falls to the final else and throws IllegalArgumentException 'did not correspond to a joinable reference'. Basic values are not joinable in Hibernate criteria.

Source

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

	private <A> SqmAttributeJoin<T, A> buildAttributeJoin(SqmPathSource<A> joinedPathSource, SqmJoinType joinType, boolean fetched) {
		if ( joinedPathSource instanceof SqmSingularPersistentAttribute<?, A> ) {
			return buildSingularJoin( (SqmSingularPersistentAttribute<T, A>) joinedPathSource, joinType, fetched );
		}
		else if ( joinedPathSource instanceof SqmBagPersistentAttribute<?, A> ) {
			return buildBagJoin( (SqmBagPersistentAttribute<T, A>) joinedPathSource, joinType, fetched );
		}
		else if ( joinedPathSource instanceof SqmListPersistentAttribute<?, A> ) {
			return buildListJoin( (SqmListPersistentAttribute<T, A>) joinedPathSource, joinType, fetched );
		}
		else if ( joinedPathSource instanceof SqmMapPersistentAttribute<?, ?, A> ) {
			return buildMapJoin( (SqmMapPersistentAttribute<T, ?, A>) joinedPathSource, joinType, fetched );
		}
		else if ( joinedPathSource instanceof SqmSetPersistentAttribute<?, A> ) {
			return buildSetJoin( (SqmSetPersistentAttribute<T, A>) joinedPathSource, joinType, fetched );
		}
		else {
			throw new IllegalArgumentException(
					String.format(
							Locale.ROOT,
							"Passed attribute [%s] did not correspond to a joinable reference [%s] relative to %s",
							joinedPathSource.getPathName(),
							joinedPathSource,
							getNavigablePath()
					)
			);
		}
	}

	private <A> SqmSingularJoin<T, A> buildSingularJoin(
			SqmSingularPersistentAttribute<? super T, A> attribute,
			SqmJoinType joinType,
			boolean fetched) {
		if ( attribute.getPathType() instanceof ManagedDomainType ) {
			return new SqmSingularJoin<>(
					this,

View on GitHub (pinned to fad1729dce)

Solutions

  1. Only join association attributes (@ManyToOne/@OneToOne/@OneToMany/@ManyToMany/@ElementCollection).
  2. For basic attributes, use the path in a WHERE predicate (equality, like, in) instead of a join.
  3. If the attribute should be an association, fix the entity mapping (add the relation annotation) and regenerate the metamodel.

Example fix

// before
root.join( root.<String>get( "name" ) ); // basic attribute -> not joinable
// after
query.where( cb.equal( root.get( "name" ), "Alice" ) );
Defensive patterns

Strategy: type-guard

Type guard

static boolean isJoinable(ManagedType<?> type, String attr) {
    Attribute<?, ?> a = type.getAttribute( attr );
    if ( a instanceof jakarta.persistence.metamodel.PluralAttribute ) return true;
    return a instanceof jakarta.persistence.metamodel.SingularAttribute<?, ?> s
        && ( s.getType() instanceof jakarta.persistence.metamodel EntityType
            || s.getType() instanceof jakarta.persistence.metamodel.EmbeddableType );
}

Prevention

When it happens

Trigger: root.join(root.get("name")) or joining a path whose attribute is a @Basic type (String, Integer, enum, Instant); join(...) on a singular attribute whose type is not an association/embeddable.

Common situations: Assuming any path can be joined like in some SQL dialects; missing @ManyToOne/@OneToMany annotations after refactoring so the attribute is basic; porting JPQL/HQL that referenced the column only in WHERE but the translation accidentally used join.

Related errors


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