hibernate/hibernate-orm · error · IllegalStateException
Could not determine a path column name after 5 tries!
Error message
Could not determine a path column name after 5 tries!
What it means
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.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java:2477
OUTER: for ( int tries = 0; tries < 5; tries++ ) {
final String name = tries == 0 ? baseName : (baseName + "_" + tries);
for ( CteColumn cteColumn : cte.getCteTable().getCteColumns() ) {
if ( name.equals( cteColumn.getColumnExpression() ) ) {
continue OUTER;
}
}
if ( cte.getSearchColumn() != null
&& name.equals( cte.getSearchColumn().getColumnExpression() ) ) {
continue;
}
if ( cte.getCycleMarkColumn() != null
&& name.equals( cte.getCycleMarkColumn().getColumnExpression() ) ) {
continue;
}
return name;
}
throw new IllegalStateException( "Could not determine a path column name after 5 tries!" );
}
protected boolean isInRecursiveQueryPart() {
return currentCteStatement != null
&& currentCteStatement.isRecursive()
&& ( (QueryGroup) ( (SelectStatement) currentCteStatement.getCteDefinition() ).getQueryPart() )
.getQueryParts().get( 1 ) == getCurrentQueryPart();
}
protected boolean isInSubquery() {
return statementStack.depth() > 1
&& statementStack.getCurrent() instanceof SelectStatement selectStatement
&& !selectStatement.getQueryPart().isRoot();
}
protected void visitCteDefinition(CteStatement cte) {
final CteStatement oldCteStatement = currentCteStatement;
currentCteStatement = cte;View on GitHub (pinned to fad1729dce)
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.
Example fix
-- before: CYCLE clause with implicit path name and all candidates taken with 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 -- after: explicit USING column name cycle id set is_cycle to true default false using visit_path
Defensive patterns
Strategy: validation
Validate before calling
// Ensure at least one emulated path name is free, or name the path column explicitly
java.util.Set<String> reserved = java.util.Set.of("path", "path_1", "path_2", "path_3", "path_4");
if ( cteColumnNames.containsAll(reserved) && !dialect.supportsRecursiveCycleClause() ) {
throw new IllegalStateException("Rename CTE columns or add an explicit USING path column");
} Try / catch
try {
return session.createQuery(graphHql, ResultDto.class).getResultList();
} catch (IllegalStateException e) {
if ( e.getMessage() != null && e.getMessage().contains("path column name") ) {
throw new IllegalStateException("CTE columns path..path_4 collide with the emulated cycle path column; add 'using <name>' to the CYCLE clause", e);
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Could not determine a depth column name after 5 tries!
- Different CTE with same name [%s] found in different set ope
- Couldn't generate CTE name for base name [%s] after %d tries
- Null is an illegal value for cycle mark values!
- Inconsistent types for cycle mark values: [{}, {}]
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/6d06c5e3c0029a1c.
Report an issue: GitHub.