hibernate/hibernate-orm · error · UnsupportedOperationException
Cte root does not have an entity type. Use getReferencedPath
Error message
Cte root does not have an entity type. Use getReferencedPathSource() instead.
What it means
SqmCteRoot is the root created for "from <cteName>" after an HQL "with" clause. CTE rows are produced by a query, not mapped to an entity, so getModel() - which must return an SqmEntityDomainType - throws UnsupportedOperationException. The message points to getReferencedPathSource(), which returns the CTE's column-shaped path source. Note that SqmCteRoot.createCorrelation() returns a SqmCorrelatedDerivedRoot, propagating the same constraint to correlated usage.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmCteRoot.java:90
return path;
}
public SqmCteStatement<T> getCte() {
return cte;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitRootCte( this );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA
@Nonnull
@Override
public SqmEntityDomainType<T> getModel() {
throw new UnsupportedOperationException( "Cte root does not have an entity type. Use getReferencedPathSource() instead." );
}
@Override
public String getEntityName() {
throw new UnsupportedOperationException( "Cte root does not have an entity type. Use getReferencedPathSource() instead." );
}
@Override
public SqmPathSource<T> getResolvedModel() {
return getReferencedPathSource();
}
@Override
@Nonnull
public SqmCorrelatedRoot<T> createCorrelation() {
return new SqmCorrelatedDerivedRoot<>( this );
}
View on GitHub (pinned to fad1729dce)
Solutions
- Use getReferencedPathSource() or getResolvedModel() to inspect the CTE column structure.
- Guard root-walking code with instanceof checks for SqmCteRoot (and SqmDerivedRoot) before calling getModel().
- If entity metadata is mandatory (e.g. for locking or second-level cache), query the mapped entity instead of the CTE, or register the CTE result table as an entity.
- For correlated subqueries over a CTE, apply the same getReferencedPathSource() pattern on the SqmCorrelatedDerivedRoot.
Example fix
// before - CTE root has no EntityType
jakarta.persistence.metamodel.EntityType<?> et =
(jakarta.persistence.metamodel.EntityType<?>) cteRoot.getModel();
// after - inspect the CTE columns via the referenced path source
SqmPathSource<?> columns = cteRoot.getReferencedPathSource();
String cteName = columns.getPathName(); Defensive patterns
Strategy: type-guard
Validate before calling
static boolean hasEntityType(jakarta.persistence.criteria.Root<?> root) {
return !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmCteRoot)
&& !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmDerivedRoot)
&& !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmFunctionRoot)
&& !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmCorrelatedDerivedRoot);
} Type guard
static boolean isCteRoot(Object node) {
return node instanceof org.hibernate.query.sqm.tree.spi.from.SqmCteRoot<?>;
} Try / catch
try {
EntityType<?> t = (EntityType<?>) root.getModel();
} catch (UnsupportedOperationException e) {
SqmPathSource<?> cteShape = ((SqmCteRoot<?>) root).getReferencedPathSource();
// drive column handling from the CTE path source
} Prevention
- Use getResolvedModel() instead of getModel() in code that may see CTE roots.
- Register CTE-containing queries in framework test corpora when adopting HQL CTEs.
- When porting from Blaze-Persistence @CTE entities, replace entity-name lookups with CTE names.
When it happens
Trigger: HQL "with t as (select ...) select x from t x" plus Java code calling root.getModel() on the CTE root (common in Specifications, entity-graph appliers, or logging layers that walk query roots); Criteria-style APIs that resolve EntityType from every root; correlating a CTE root into a subquery and then asking for its model.
Common situations: Adopting Hibernate 6.6/7 CTE-in-HQL features in codebases where generic root-processing assumed entity roots; recursive-CTE queries for tree traversals hitting framework code that expects entities; migrating Blaze-Persistence CTE queries (which use @CTE entities) to native HQL CTEs, where getModel() no longer applies.
Related errors
- CTE joins can not be treated
- Could not interpret attribute '%s' of basic-valued path '%s'
- Boolean expression does not support max()
- Boolean expression does not support min()
- Embeddable paths cannot be TREAT-ed to an entity type
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/4965992c7ec2093f.
Report an issue: GitHub.