{"record":{"id":"8b9254b6569f65dc","repo":"hibernate/hibernate-orm","slug":"illegal-cte-name-s-names-must-start-with-an-al","errorCode":null,"errorMessage":"Illegal CTE name [%s]. Names must start with an alphabetic character!","messagePattern":"Illegal CTE name \\[(.+?)\\]\\. Names must start with an alphabetic character!","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/AbstractSqmDmlStatement.java","lineNumber":159,"sourceCode":"\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\tprivate <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()\n\t\t);\n\t\tif ( cteStatements.putIfAbsent( name, cteStatement ) != null ) {\n\t\t\tthrow new IllegalArgumentException( \"A CTE with the label \" + cteStatement.getCteTable().getCteName() + \" already exists\" );","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/AbstractSqmDmlStatement.java#L141-L177","documentation":"Same validator (validateCteName) rejects a non-blank CTE label whose first character fails Character.isAlphabetic. The label of a CTE registered on a criteria DML statement must start with a letter; digits, underscores, '$' or other symbols as the first character throw IllegalArgumentException. The rest of the name is not validated here.","triggerScenarios":"with(\"_ids\", cteQuery), with(\"1st_stage\", cteQuery) or withRecursiveUnionDistinct(\"$foo\", base, producer) on a criteria insert/update/delete statement. Any label whose charAt(0) is not alphabetic (leading '_', digit, '$', '-', etc.).","commonSituations":"Reusing database naming conventions (leading underscore snake_case), generated numeric-prefixed labels, or names prefixed with '$'/'#' tokens copied from HQL aliases or table aliases.","solutions":["Start the label with an ASCII letter, e.g. \"cte_ids\" instead of \"_ids\".","Validate dynamic labels with a regex like ^\\p{IsAlphabetic} before passing them.","Use the unnamed with()/withRecursiveUnionAll() overloads to let Hibernate generate a legal alias."],"exampleFix":"// before\ndelete.withRecursiveUnionAll( \"1_levels\", base, producer ); // starts with digit\n// after\ndelete.withRecursiveUnionAll( \"levels\", base, producer );","handlingStrategy":"validation","validationCode":"private static final Pattern LEGAL_CTE = Pattern.compile( \"^\\\\p{IsAlphabetic}\" );\nstatic boolean isLegalCteName(String name) {\n    return name != null && !name.isBlank() && LEGAL_CTE.matcher( name ).find();\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Start generated CTE labels with a fixed letter prefix such as \"cte_\".","Do not copy DB identifier conventions (leading underscore, digit-first) into criteria CTE labels.","Cover label format in unit tests for query-builder helpers."],"tags":["hibernate","criteria-api","cte","naming","illegal-argument"],"backgroundTag":"invalid-identifier-name","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}