{"record":{"id":"83afaa86b436f1c4","repo":"hibernate/hibernate-orm","slug":"lhs-cannot-be-null-for-a-sub-navigable-reference","errorCode":null,"errorMessage":"LHS cannot be null for a sub-navigable reference - {}","messagePattern":"LHS cannot be null for a sub-navigable reference - (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java","lineNumber":383,"sourceCode":"\t\t\t);\n\t\t\treturn (SqmJoin<D, J>) join;\n\t\t}\n\t\telse {\n\t\t\treturn new SqmSingularJoin<>(\n\t\t\t\t\tlhs,\n\t\t\t\t\tthis,\n\t\t\t\t\talias,\n\t\t\t\t\tjoinType,\n\t\t\t\t\tfetched,\n\t\t\t\t\tnodeBuilder\n\t\t\t);\n\t\t}\n\t}\n\n\t@Override\n\tpublic NavigablePath createNavigablePath(SqmPath<?> parent, @Nullable String alias) {\n\t\tif ( parent == null ) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"LHS cannot be null for a sub-navigable reference - \" + getName()\n\t\t\t);\n\t\t}\n\n\t\treturn buildSubNavigablePath( getParentNavigablePath( parent ), getName(), alias );\n\t}\n\n\tpublic static class ComparableAttributeImpl<D, J extends Comparable<? super J>>\n\t\t\textends SingularAttributeImpl<D, J>\n\t\t\timplements ComparableAttribute<D, J> {\n\t\tpublic ComparableAttributeImpl(\n\t\t\t\tManagedDomainType<D> declaringType,\n\t\t\t\tString name,\n\t\t\t\tAttributeClassification attributeClassification,\n\t\t\t\tSqmDomainType<J> attributeType,\n\t\t\t\tJavaType<?> relationalJavaType,\n\t\t\t\tMember member,\n\t\t\t\tboolean isIdentifier,","sourceCodeStart":365,"sourceCodeEnd":401,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java#L365-L401","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (custom SQM building)\nSqmPath<?> p = singularAttribute.createSqmPath(null, null); // 'LHS cannot be null'\n\n// after\nSqmRoot<Order> root = query.getRoots().iterator().next();\nSqmPath<?> p = singularAttribute.createSqmPath(root, null); // attached to a lhs","handlingStrategy":"validation","validationCode":"// Custom SQM building: always establish the lhs first and pass it through\nif (parent == null) {\n  throw new IllegalArgumentException(\n      \"Cannot create path for attribute '\" + attribute.getName() + \"' without a parent; create the root/join first\");\n}\nSqmPath<?> path = attribute.createSqmPath(parent, alias);","typeGuard":null,"tryCatchPattern":"try {\n  return attribute.createSqmPath(lhs, alias);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"LHS cannot be null\")) {\n    throw new IllegalStateException(\"Path for '\" + attribute.getName() + \"' built without a root — check path construction order\", e);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["hibernate","sqm","criteria-api","internal-api"],"backgroundTag":"invalid-criteria-path","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}