{"record":{"id":"120c58faf6672de0","repo":"hibernate/hibernate-orm","slug":"criteria-did-not-define-any-query-roots-120c58","errorCode":null,"errorMessage":"Criteria did not define any query roots","messagePattern":"Criteria did not define any query roots","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java","lineNumber":1032,"sourceCode":"\t\t\tRestriction<? super X> restriction) {\n\t\t//noinspection unchecked\n\t\tfinal var root = (JpaRoot<X>) sqmStatement.getRoot( 0, resultType );\n\t\treturn (SqmPredicate) restriction.toPredicate( root, sqmStatement.nodeBuilder() );\n\t}\n\n\tpublic static void validateCriteriaQuery(SqmQueryPart<?> queryPart) {\n\t\tvalidateCriteriaQueryStructure( queryPart );\n\t\tSqmCriteriaRootValidator.validate( queryPart );\n\t}\n\n\tprivate static void validateCriteriaQueryStructure(SqmQueryPart<?> queryPart) {\n\t\tif ( queryPart instanceof SqmQuerySpec<?> sqmQuerySpec ) {\n\t\t\tfinal var selectClause = sqmQuerySpec.getSelectClause();\n\t\t\tif ( selectClause.getSelections().isEmpty() ) {\n\t\t\t\t// make sure there is at least one root\n\t\t\t\tfinal var sqmRoots = sqmQuerySpec.getFromClause().getRoots();\n\t\t\t\tif ( sqmRoots == null || sqmRoots.isEmpty() ) {\n\t\t\t\t\tthrow new IllegalArgumentException( \"Criteria did not define any query roots\" );\n\t\t\t\t}\n\t\t\t\tif ( sqmRoots.size() != 1 ) {\n\t\t\t\t\tthrow new IllegalArgumentException( \"Criteria has multiple query roots\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ( queryPart instanceof SqmQueryGroup<?> queryGroup ) {\n\t\t\tfor ( var part : queryGroup.getQueryParts() ) {\n\t\t\t\tvalidateCriteriaQueryStructure( part );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tassert false;\n\t\t}\n\t}\n\n\tpublic static void validateCriteriaTree(SqmDeleteStatement<?> statement) {\n\t\tSqmCriteriaRootValidator.validate( statement );","sourceCodeStart":1014,"sourceCodeEnd":1050,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java#L1014-L1050","documentation":"Thrown as IllegalArgumentException by SqmUtil.validateCriteriaQueryStructure when a CriteriaQuery part has an empty select clause and its from-clause has no roots. When nothing is selected, Hibernate implicitly selects the single root — with zero roots there is nothing to query, so criteria validation fails before execution. The check recurses into query groups, so a set-operation member without roots also triggers it.","triggerScenarios":"em.createQuery(cb.createQuery()) or cb.createQuery(Person.class) used without ever calling .from(Person.class); a dynamically assembled CriteriaQuery whose from() call was skipped by a filter/condition bug; a CriteriaDefinition or query group where one branch never got a root.","commonSituations":"Criteria built from user-supplied filter specs where an empty filter set leads to an empty query; refactoring that moves from() into a conditional block; copy-paste criteria templates missing the from() line; new tests constructing criteria stubs.","solutions":["Add at least one root: cq.from(Person.class)","If the criteria is optional, skip query execution entirely when no root/entity was configured","Guard dynamic criteria builders: require the entity class parameter up front and call from(entityClass) unconditionally","For query groups, ensure every member part has its own root"],"exampleFix":"// before\nCriteriaQuery<Person> cq = cb.createQuery(Person.class);\nList<Person> people = em.createQuery(cq).getResultList(); // no from() called\n// after\nCriteriaQuery<Person> cq = cb.createQuery(Person.class);\ncq.from(Person.class);\nList<Person> people = em.createQuery(cq).getResultList();","handlingStrategy":"validation","validationCode":"static <X> CriteriaQuery<X> requireRoot(CriteriaQuery<X> cq, Class<X> entity) {\n    if (cq.getRoots().isEmpty()) {\n        cq.from(entity);\n    }\n    return cq;\n}\n// em.createQuery(requireRoot(cq, Person.class)).getResultList();","typeGuard":null,"tryCatchPattern":"try {\n    return em.createQuery(cq).getResultList();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"query roots\")) {\n        throw new IllegalStateException(\"Criteria built without a root: \" + cq, e);\n    }\n    throw e;\n}","preventionTips":["Always call from(entityClass) immediately after cb.createQuery()","Guard dynamic criteria builders with a non-null entity parameter","Skip execution and return an empty list when no entity type is configured"],"tags":["hibernate","criteria-api","jpa","query-validation"],"backgroundTag":"criteria-missing-query-root","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}