{"record":{"id":"77ce614413ac458c","repo":"hibernate/hibernate-orm","slug":"illegal-empty-cte-name-77ce61","errorCode":null,"errorMessage":"Illegal empty CTE name","messagePattern":"Illegal empty CTE name","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/select/AbstractSqmSelectQuery.java","lineNumber":185,"sourceCode":"\tpublic <X> JpaCteCriteria<X> withRecursiveUnionAll(\n\t\t\t@Nonnull String name,\n\t\t\t@Nonnull AbstractQuery<X> baseCriteria,\n\t\t\t@Nonnull Function<JpaCteCriteria<X>, AbstractQuery<X>> recursiveCriteriaProducer) {\n\t\treturn withInternal( validateCteName( name ), baseCriteria, false, recursiveCriteriaProducer );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic <X> JpaCteCriteria<X> withRecursiveUnionDistinct(\n\t\t\t@Nonnull String name,\n\t\t\t@Nonnull AbstractQuery<X> baseCriteria,\n\t\t\t@Nonnull Function<JpaCteCriteria<X>, AbstractQuery<X>> recursiveCriteriaProducer) {\n\t\treturn withInternal( validateCteName( name ), baseCriteria, true, recursiveCriteriaProducer );\n\t}\n\n\tprivate String validateCteName(String name) {\n\t\tif ( name == null || name.isBlank() ) {\n\t\t\tthrow new IllegalArgumentException( \"Illegal empty CTE name\" );\n\t\t}\n\t\tif ( !isAlphabetic( name.charAt( 0 ) ) ) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\"Illegal CTE name [%s]. Names must start with an alphabetic character!\",\n\t\t\t\t\t\t\tname\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\treturn name;\n\t}\n\n\tprotected <X> JpaCteCriteria<X> withInternal(String name, AbstractQuery<X> criteria) {\n\t\tfinal var cteStatement = new SqmCteStatement<>(\n\t\t\t\tname,\n\t\t\t\t(SqmSelectQuery<X>) criteria,\n\t\t\t\tthis,\n\t\t\t\tnodeBuilder()","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/select/AbstractSqmSelectQuery.java#L167-L203","documentation":"AbstractSqmSelectQuery.validateCteName throws IllegalArgumentException when the name passed to a with*(...) CTE builder (with, withRecursiveUnionAll, withRecursiveUnionDistinct) is null or blank. Criteria CTEs become SQL common table expressions whose names are identifiers; an empty label cannot be rendered, and since criteria builds the tree in Java there is no parser to catch it — hence explicit validation at registration time.","triggerScenarios":"Criteria: `query.with( \"\", subquery )`, `query.with( null, sub )`, or a name built by string concat/configuration that yields blank (e.g. prefix stripped by a naming strategy leaving \"\"); withRecursiveUnionAll(name, ...) with whitespace-only name.","commonSituations":"CTE names derived from dynamic input (report names, i18n keys) that can be empty; optional-CTE patterns where the name comes from a map key that was never set; copy-paste of HQL cte examples into criteria where the name literal was dropped.","solutions":["Pass a non-empty alphanumeric name starting with a letter","Validate/normalize dynamic names before use: null/blank check plus a default fallback label in your builder code","Load CTE names from a checked registry/enum rather than free-form strings","Unit-test the query factory with all name sources it can receive"],"exampleFix":"// before\nString cteName = System.getenv(\"CTE_NAME\"); // may be unset -> null\nquery.with( cteName, sub ); // IllegalArgumentException\n\n// after\nString cteName = Objects.requireNonNullElse( System.getenv(\"CTE_NAME\"), \"results\" );\nquery.with( cteName, sub );","handlingStrategy":"validation","validationCode":"if (name == null || name.isBlank()) {\n    throw new IllegalArgumentException(\"CTE name must be non-empty\");\n}\nquery.with(name, sub);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Route all CTE naming through one helper that rejects blank names","Never feed raw config/env values as CTE names without validation","Default missing names to a stable constant"],"tags":["hibernate","criteria-api","cte","validation","naming"],"backgroundTag":"query-identifier-validation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}