hibernate/hibernate-orm · error · IllegalArgumentException
LHS cannot be null for a sub-navigable reference - {}
Error message
LHS cannot be null for a sub-navigable reference - {} What it means
SingularAttributeImpl.createNavigablePath(SqmPath parent, alias) requires a non-null parent (the LHS — root or join the attribute hangs off). A null parent means a sub-navigable reference was requested with nothing to attach to, so it throws IllegalArgumentException naming the attribute. Reached through SQM building: criteria paths, HQL translation, or direct SQM metamodel use.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java:383
);
return (SqmJoin<D, J>) join;
}
else {
return new SqmSingularJoin<>(
lhs,
this,
alias,
joinType,
fetched,
nodeBuilder
);
}
}
@Override
public NavigablePath createNavigablePath(SqmPath<?> parent, @Nullable String alias) {
if ( parent == null ) {
throw new IllegalArgumentException(
"LHS cannot be null for a sub-navigable reference - " + getName()
);
}
return buildSubNavigablePath( getParentNavigablePath( parent ), getName(), alias );
}
public static class ComparableAttributeImpl<D, J extends Comparable<? super J>>
extends SingularAttributeImpl<D, J>
implements ComparableAttribute<D, J> {
public ComparableAttributeImpl(
ManagedDomainType<D> declaringType,
String name,
AttributeClassification attributeClassification,
SqmDomainType<J> attributeType,
JavaType<?> relationalJavaType,
Member member,
boolean isIdentifier,View on GitHub (pinned to fad1729dce)
Solutions
- Create the root/join first and derive attribute paths from it: root.get(attribute) / from.join(...)
- In custom SQM code, pass the enclosing SqmFrom as lhs — never null
- Check for null parent before calling createNavigablePath and fail with your own diagnostic naming the attribute and query
Example fix
// before (custom SQM building) SqmPath<?> p = singularAttribute.createSqmPath(null, null); // 'LHS cannot be null' // after SqmRoot<Order> root = query.getRoots().iterator().next(); SqmPath<?> p = singularAttribute.createSqmPath(root, null); // attached to a lhs
Defensive patterns
Strategy: validation
Validate before calling
// Custom SQM building: always establish the lhs first and pass it through
if (parent == null) {
throw new IllegalArgumentException(
"Cannot create path for attribute '" + attribute.getName() + "' without a parent; create the root/join first");
}
SqmPath<?> path = attribute.createSqmPath(parent, alias); Try / catch
try {
return attribute.createSqmPath(lhs, alias);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("LHS cannot be null")) {
throw new IllegalStateException("Path for '" + attribute.getName() + "' built without a root — check path construction order", e);
}
throw e;
} Prevention
- In custom criteria/SQM code, construct roots/joins before any attribute path and thread the lhs explicitly
- Prefer the public JPA Criteria API (root.get(...)) — it cannot produce a detached sub-navigable path
- Null-check the parent at your API boundary with a diagnostic naming the attribute and the query being built
When it happens
Trigger: Calling attribute.createSqmPath(null) or building an SqmPath for an attribute without first creating the SqmFrom it belongs to (root.get(...) done out of order); custom criteria extensions or QueryEngine integrations constructing paths top-down without a lhs.
Common situations: Custom query infrastructure (tenant filters, specification libraries) that builds paths from metamodel attributes; refactors that reorder path construction; code ported from native Criteria where path chaining differs.
Related errors
- MappedSuperclassType cannot be used to create an SqmPath - t
- Not correlated
- Could not interpret attribute '%s' of basic-valued path '%s'
- Boolean expression does not support max()
- Boolean expression does not support min()
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/83afaa86b436f1c4.
Report an issue: GitHub.