{"record":{"id":"b4eb00fe5022d81d","repo":"hibernate/hibernate-orm","slug":"could-not-find-root","errorCode":null,"errorMessage":"Could not find root","messagePattern":"Could not find root","errorType":"exception","errorClass":"ParsingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmPath.java","lineNumber":131,"sourceCode":"\t<S extends T> SqmTreatedPath<T,S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias);\n\n\t@Nonnull\n\t<S extends T> SqmTreatedPath<T,S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias);\n\n\t@Nonnull\n\t<S extends T> SqmTreatedPath<T,S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias, boolean fetch);\n\n\t@Nonnull\n\t<S extends T> SqmTreatedPath<T,S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias, boolean fetch);\n\n\t@Nonnull\n\tdefault SqmRoot<?> findRoot() {\n\t\tfinal var lhs = getLhs();\n\t\tif ( lhs != null ) {\n\t\t\treturn lhs.findRoot();\n\t\t}\n\n\t\tthrow new ParsingException( \"Could not find root\" );\n\t}\n\n\tSqmPath<?> resolvePathPart(\n\t\t\tString name,\n\t\t\tboolean isTerminal,\n\t\t\tSqmCreationState creationState);\n\n\t@Override\n\tdefault SqmPath<?> resolveIndexedAccess(\n\t\t\tSqmExpression<?> selector,\n\t\t\tboolean isTerminal,\n\t\t\tSqmCreationState creationState) {\n\t\tthrow new SemanticException( \"Index operator applied to non-plural path '\" + getNavigablePath() + \"'\" );\n\t}\n\n\t/**\n\t * Get this path's actual resolved model, i.e. the concrete type for generic attributes.\n\t */","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmPath.java#L113-L149","documentation":"SqmPath.findRoot() walks the getLhs() chain to find the SqmRoot a path belongs to; roots and root-like joins (SqmRoot, SqmCrossJoin, SqmEntityJoin, SqmCteJoin, SqmDerivedJoin, correlations) override it to return themselves. If the walk reaches a path whose LHS is null without meeting a root - a detached or partially built SQM path - the default method throws ParsingException('Could not find root') from org.hibernate.query.sqm. It fires during SQM construction (join registration in AbstractSqmFrom, join-predicate resolution in QualifiedJoinPredicatePathConsumer), so it surfaces as a parse failure of the HQL/criteria query being built.","triggerScenarios":"Calling findRoot() - directly or indirectly via join creation (SqmFrom.join/addOrderedJoin) or HQL join-predicate parsing - on an SqmPath that is not linked to an SqmRoot: hand-built SQM trees, a path created standalone from its SqmPathSource (lhs never set), or SQM nodes copied/reused between queries without SqmCopyContext.","commonSituations":"Programmatic SQM construction in custom query infrastructure or tests; reusing Root/Join objects from one criteria query inside another; partial copies of SQM subtrees; Hibernate version upgrades that changed LHS wiring - if hit with plain HQL and no manual SQM, treat it as a parser regression.","solutions":["Create every path from the query's root (root.join(...), root.get(...)) instead of constructing SqmPath nodes directly","When cloning SQM trees, use node.copy(SqmCopyContext) so LHS links are preserved","Correlate subqueries through createCorrelation()/SqmSubQuery so the LHS chain stays intact","If no manual SQM is involved, reduce the HQL to a minimal reproduction and report it as a Hibernate parser bug"],"exampleFix":"// before - detached path, lhs is null\nSqmPath<Phone> p = phonePathSource.createSqmPath( null );\np.findRoot(); // ParsingException: Could not find root\n\n// after - build from the query's root\nSqmRoot<Person> root = query.from( Person.class );\nSqmMapJoin<Person, String, Phone> phones = root.join( Person_.phones );\nphones.findRoot(); // returns root","handlingStrategy":"try-catch","validationCode":"import org.hibernate.query.sqm.tree.spi.domain.SqmPath;\nimport org.hibernate.query.sqm.tree.spi.from.SqmRoot;\n\n/** Returns the root this path belongs to, or null if the path is detached. */\nstatic SqmRoot<?> rootOrNull(SqmPath<?> path) {\n    for ( SqmPath<?> p = path; p != null; p = p.getLhs() ) {\n        if ( p instanceof SqmRoot<?> r ) {\n            return r;\n        }\n    }\n    return null; // findRoot() on such a path throws 'Could not find root'\n}","typeGuard":"static boolean isAttachedToRoot(SqmPath<?> path) {\n    for ( SqmPath<?> p = path; p != null; p = p.getLhs() ) {\n        if ( p instanceof SqmRoot<?> ) {\n            return true;\n        }\n    }\n    return false;\n}","tryCatchPattern":"try {\n    return session.createQuery( hql, Person.class ).list();\n} catch ( org.hibernate.query.sqm.ParsingException e ) {\n    if ( \"Could not find root\".equals( e.getMessage() ) ) {\n        throw new IllegalStateException( \"Query uses a path detached from its root: \" + hql, e );\n    }\n    throw e;\n}","preventionTips":["Always create paths from the query root (root.join/root.get), never standalone SqmPath objects","Use node.copy(SqmCopyContext) when cloning SQM subtrees so LHS links survive","Never share Root/Join/SQM nodes between different queries","Correlate subqueries via createCorrelation() instead of manual wiring","If hit with plain HQL and no manual SQM, minimize and report - it indicates a parser defect"],"tags":["hibernate","hql","sqm","parsing","path-resolution","criteria-api"],"backgroundTag":"sqm-path-missing-root","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}