{"record":{"id":"6d06c5e3c0029a1c","repo":"hibernate/hibernate-orm","slug":"could-not-determine-a-path-column-name-after-5-tri","errorCode":null,"errorMessage":"Could not determine a path column name after 5 tries!","messagePattern":"Could not determine a path column name after 5 tries!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java","lineNumber":2477,"sourceCode":"\t\tOUTER: for ( int tries = 0; tries < 5; tries++ ) {\n\t\t\tfinal String name = tries == 0 ? baseName : (baseName + \"_\" + tries);\n\t\t\tfor ( CteColumn cteColumn : cte.getCteTable().getCteColumns() ) {\n\t\t\t\tif ( name.equals( cteColumn.getColumnExpression() ) ) {\n\t\t\t\t\tcontinue OUTER;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( cte.getSearchColumn() != null\n\t\t\t\t\t&& name.equals( cte.getSearchColumn().getColumnExpression() ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ( cte.getCycleMarkColumn() != null\n\t\t\t\t\t&& name.equals( cte.getCycleMarkColumn().getColumnExpression() ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\treturn name;\n\t\t}\n\t\tthrow new IllegalStateException( \"Could not determine a path column name after 5 tries!\" );\n\t}\n\n\tprotected boolean isInRecursiveQueryPart() {\n\t\treturn currentCteStatement != null\n\t\t\t&& currentCteStatement.isRecursive()\n\t\t\t&& ( (QueryGroup) ( (SelectStatement) currentCteStatement.getCteDefinition() ).getQueryPart() )\n\t\t\t\t\t.getQueryParts().get( 1 ) == getCurrentQueryPart();\n\t}\n\n\tprotected boolean isInSubquery() {\n\t\treturn statementStack.depth() > 1\n\t\t\t&& statementStack.getCurrent() instanceof SelectStatement selectStatement\n\t\t\t&& !selectStatement.getQueryPart().isRoot();\n\t}\n\n\tprotected void visitCteDefinition(CteStatement cte) {\n\t\tfinal CteStatement oldCteStatement = currentCteStatement;\n\t\tcurrentCteStatement = cte;","sourceCodeStart":2459,"sourceCodeEnd":2495,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java#L2459-L2495","documentation":"When emulating a CYCLE clause on a dialect without native 'cycle ... using' support, determineCyclePathColumnName must invent the column that stores the visited-path array. If the query did not name it explicitly (no USING path_col), it tries 'path', 'path_1' .. 'path_4', skipping names taken by CTE columns, the search column, or the cycle mark column. Exhausting all five candidates throws IllegalStateException.","triggerScenarios":"A recursive CTE with a CYCLE clause lacking an explicit path column (HQL 'cycle col set mark to true default false' without 'using <path_col>'), on a dialect where supportsRecursiveCycleClause()/supportsRecursiveCycleUsingClause() is false, whose CTE columns already occupy all of path, path_1, path_2, path_3, path_4 (or those collide with search/cycle mark columns).","commonSituations":"Graph-traversal CTEs that already project materialized path columns (path, path_1, ... for alternate routes); tree structures where 'path' is a natural business column name; migrations that added path_N columns for history tracking.","solutions":["Name the cycle path column explicitly with the USING clause ('cycle ... set ... default ... using visit_path') so no name has to be invented.","Rename the CTE's own columns so at least one of path, path_1..path_4 stays free.","Handle cycle protection manually with a NOT EXISTS/anti-join predicate in the recursive part instead of the CYCLE clause.","Use a native query if the schema column names cannot be changed."],"exampleFix":"-- before: CYCLE clause with implicit path name and all candidates taken\nwith recursive t(id, path, path_1, path_2, path_3, path_4) as (...) cycle id set is_cycle to true default false select * from t\n-- after: explicit USING column name\ncycle id set is_cycle to true default false using visit_path","handlingStrategy":"validation","validationCode":"// Ensure at least one emulated path name is free, or name the path column explicitly\njava.util.Set<String> reserved = java.util.Set.of(\"path\", \"path_1\", \"path_2\", \"path_3\", \"path_4\");\nif ( cteColumnNames.containsAll(reserved) && !dialect.supportsRecursiveCycleClause() ) {\n    throw new IllegalStateException(\"Rename CTE columns or add an explicit USING path column\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(graphHql, ResultDto.class).getResultList();\n} catch (IllegalStateException e) {\n    if ( e.getMessage() != null && e.getMessage().contains(\"path column name\") ) {\n        throw new IllegalStateException(\"CTE columns path..path_4 collide with the emulated cycle path column; add 'using <name>' to the CYCLE clause\", e);\n    }\n    throw e;\n}","preventionTips":["Always write the CYCLE clause with an explicit path column ('cycle ... set ... default ... using visit_path') so Hibernate never has to invent a name.","Avoid projecting columns literally named path/path_1..path_4 in recursive CTEs that also use CYCLE.","For graph traversal where 'path' is a natural domain column, rename the domain column or rely on manual cycle protection (anti-join) instead."],"tags":["hibernate","recursive-cte","cycle-clause","name-collision"],"backgroundTag":"column-name-collision","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}