hibernate/hibernate-orm · error · UnsupportedOperationException

Correlated derived root does not have an entity type. Use ge

Error message

Correlated derived root does not have an entity type. Use getReferencedPathSource() instead.

What it means

SqmCorrelatedDerivedRoot wraps a subquery root that was correlated into an inner query and whose outer referent is a derived root (a "from (select ...)" group, often created via SqmCteRoot.createCorrelation() or correlating a derived root inside a subquery). Such a root denotes query-derived rows, not a mapped entity, so the JPA Root contract getModel() (returning an EntityType) cannot be honored; Hibernate throws UnsupportedOperationException and the message tells you to use getReferencedPathSource() to inspect the row type instead.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmCorrelatedDerivedRoot.java:54

		final var existing = context.getCopy( this );
		if ( existing != null ) {
			return existing;
		}
		final var path = context.registerCopy(
				this,
				new SqmCorrelatedDerivedRoot<>( getCorrelationParent().copy( context ) )
		);
		copyTo( path, context );
		return path;
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// JPA

	@Nonnull
	@Override
	public SqmEntityDomainType<T> getModel() {
		throw new UnsupportedOperationException( "Correlated derived root does not have an entity type. Use getReferencedPathSource() instead." );
	}

	@Override
	public String getEntityName() {
		throw new UnsupportedOperationException( "Correlated derived root does not have an entity type. Use getReferencedPathSource() instead." );
	}

	@Override
	public SqmPathSource<T> getResolvedModel() {
		return getReferencedPathSource();
	}

}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use getReferencedPathSource() (or getResolvedModel(), which delegates to it) to obtain the SqmPathSource describing the derived rows.
  2. Guard generic root-handling code: skip or special-case roots that are SqmDerivedRoot, SqmCteRoot, or SqmCorrelatedDerivedRoot before calling getModel().
  3. When an EntityType is genuinely required, query the underlying mapped entity directly instead of a derived table.
  4. Catch UnsupportedOperationException as a last resort in framework code and fall back to getJavaType() metadata.

Example fix

// before - breaks when the correlated root wraps a derived/CTE root
EntityType<?> t = (EntityType<?>) root.getModel();
String name = t.getName();

// after - ask for the referenced path source, which always exists
String name = ((org.hibernate.query.sqm.tree.spi.domain.SqmPath<?>) root)
        .getReferencedPathSource().getPathName();
Defensive patterns

Strategy: type-guard

Validate before calling

// In generic root walkers, probe for entity-backed roots before using getModel()
static boolean hasEntityType(jakarta.persistence.criteria.Root<?> root) {
    return !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmCorrelatedDerivedRoot)
        && !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmDerivedRoot)
        && !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmCteRoot)
        && !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmFunctionRoot);
}

Type guard

static boolean isEntityBackedRoot(Object sqmRoot) {
    return sqmRoot instanceof org.hibernate.query.sqm.tree.spi.from.SqmRoot
        || sqmRoot instanceof org.hibernate.query.sqm.tree.spi.from.SqmCrossJoin
        || sqmRoot instanceof org.hibernate.query.sqm.tree.spi.from.SqmEntityJoin;
}

Try / catch

try {
    return root.getModel();
} catch (UnsupportedOperationException e) {
    // derived/CTE/correlated-derived roots: no EntityType available
    return null; // caller falls back to getReferencedPathSource() / getJavaType()
}

Prevention

When it happens

Trigger: HQL with a derived table correlated into a subquery, e.g. "select e from Employee e where exists (select 1 from (select ...) d where d.x = e.x)" combined with Java code that calls root.getModel() on the subquery root; Criteria code doing subquery.correlate(derivedRoot).getModel(); generic framework code (Specifications, auditors, entity-graph appliers) that unconditionally calls getModel() on every root of every query.

Common situations: Spring Data JPA or in-house specification layers that resolve root.getModel().getName() for aliasing or logging on arbitrary queries; migrating queries from entity roots to CTE/derived-table style (Hibernate 6.6+/7 improved support) and legacy root-processing code breaking; correlation of a CTE root (SqmCteRoot.createCorrelation returns SqmCorrelatedDerivedRoot).

Related errors


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