hibernate/hibernate-orm · error · InterpretationException

Couldn't generate CTE name for base name [%s] after %d tries

Error message

Couldn't generate CTE name for base name [%s] after %d tries

What it means

Thrown during SQM-to-SQL translation when Hibernate must invent a SQL-level name for a CTE and every candidate collides. getCteName() derives a base name from the SqmCteTable label (or a synthetic 'cte<n>'), and generateCteName() tries baseName, then baseName_0 through baseName_3 (5 tries) against cteNameMapping; if all 5 are taken, translation aborts with an InterpretationException.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/sql/spi/BaseSqmToSqlAstConverter.java:1888

			// route the CTE name through the IdentifierHelper so it gets the same quoting
			// treatment (reserved words, global/auto quoting) as any other identifier
			final String cteName = getSessionFactory().getJdbcServices().getJdbcEnvironment()
					.getIdentifierHelper().toIdentifier( generatedName ).render( getDialect() );
			cteNameMapping.put( key, cteName );
			return cteName;
		}
	}

	private String generateCteName(String baseName) {
		String name = baseName;
		int maxTries = 5;
		for ( int i = 0; i < maxTries; i++ ) {
			if ( !cteNameMapping.containsKey( name ) ) {
				return name;
			}
			name = baseName + "_" + i;
		}
		throw new InterpretationException(
				String.format(
						"Couldn't generate CTE name for base name [%s] after %d tries",
						baseName,
						maxTries
				)
		);
	}

	private Literal getLiteral(SqmLiteral<?> value) {
		return value == null ? null : (Literal) visitLiteral( value );
	}

	protected List<SearchClauseSpecification> visitSearchBySpecifications(
			CteTable cteTable,
			List<JpaSearchOrder> searchBySpecifications) {
		if ( searchBySpecifications == null || searchBySpecifications.isEmpty() ) {
			return null;
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Give every CTE in the statement a unique explicit label instead of relying on generated names
  2. Reduce the number of CTEs: merge equivalent CTEs or inline the ones used only once
  3. Split the statement into multiple sequential queries so each statement registers fewer CTEs
  4. If labels are already unique and it still fails, file a Hibernate JIRA with the query - a genuinely unique base name should never exhaust 5 tries

Example fix

// before (criteria, same label reused across many branches)
cteContainer.with("data", dataQuery);
...
// after: unique labels per CTE
cteContainer.with("data_" + branchIndex, dataQuery);
Defensive patterns

Strategy: try-catch

Validate before calling

// Before executing, sanity-check that CTE labels in one statement are unique
// (HQL): count labels in the with-clause
java.util.List<String> labels = java.util.Arrays.stream(hql.split("\\s+"))
    .filter(w -> w.equalsIgnoreCase("with") || w.contains(",")) .count() > 5
        ? java.util.Collections.singletonList("review-cte-count")
        : java.util.Collections.emptyList();

Try / catch

try {
    Query<?> q = session.createQuery(hql);
    return q.getResultList();
} catch (org.hibernate.query.sqm.InterpretationException e) {
    log.error("Query failed to translate: {}", hql, e);
    throw new QueryTranslationFailure(hql, e); // keep the HQL with the error for diagnosis
}

Prevention

When it happens

Trigger: A single HQL statement that registers six or more CTEs whose labels collapse to the same generated base name: many subqueries or union branches re-declaring the same CTE label, a criteria query with JpaCteCriteria added repeatedly under one name, or programmatically generated with-clauses where SqmCteTables carry no explicit name and their fallback names collide after identifier rendering.

Common situations: Programmatically built queries (criteria + CTE containers) in reporting/data-pipeline code; heavy use of union all with shared CTE labels; upgrades between Hibernate versions where CTE name generation changed; test suites generating very wide with-clauses.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/399c72af818cb418. Report an issue: GitHub.