hibernate/hibernate-orm · error · UnknownEntityException

Could not resolve root entity '${name}'

Error message

Could not resolve root entity '${name}'

What it means

The final fallback of root resolution: the from-clause name is not a mapped entity, not resolvable as a correlation, and no CTE with that name exists, so UnknownEntityException 'Could not resolve root entity' is thrown. This is the classic 'entity not mapped' error for the primary from-clause root.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java:2185

							false
					);
				}
				dotIdentifierConsumer.consumeIdentifier(
						entityNameParseTreeChildren.get( lastIdx ).getText(),
						false,
						true
				);
				return sqmCorrelation.getCorrelatedRoot();
			}
			throw new SemanticException( "Could not resolve entity or correlation path '" + name + "'", query );
		}
		final var cteStatement = findCteStatement( name );
		if ( cteStatement != null ) {
			final var root = new SqmCteRoot<>( cteStatement, alias);
			pathRegistry.register( root );
			return root;
		}
		throw new UnknownEntityException( "Could not resolve root entity '" + name + "'", name);
	}

	@Override
	public SqmCteStatement<?> findCteStatement(String name) {
		if ( currentPotentialRecursiveCte != null && name.equals( currentPotentialRecursiveCte.getName() ) ) {
			return (SqmCteStatement<?>) currentPotentialRecursiveCte;
		}
		return processingStateStack.findCurrentFirstWithParameter( name, SemanticQueryBuilder::matchCteStatement );
	}

	private static SqmCteStatement<?> matchCteStatement(SqmCreationProcessingState state, String n) {
		return state.getProcessingQuery() instanceof SqmCteContainer container
				? container.getCteStatement( n )
				: null;
	}

	@Override
	public SqmRoot<?> visitRootSubquery(HqlParser.RootSubqueryContext ctx) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use the exact mapped entity name (check @Entity(name=...) and metamodel entity names, mind case)
  2. Ensure the entity class is scanned by the persistence unit
  3. For CTE roots, match the name declared in the WITH clause exactly
  4. If the name collides, use the fully qualified class name if registered, or disambiguate with @Entity(name=...)

Example fix

// before
select e from EMPLOYEE e

// after
select e from Employee e
Defensive patterns

Strategy: validation

Validate before calling

static boolean isMappedEntityName(EntityManagerFactory emf, String name) {
    for (jakarta.persistence.metamodel.EntityType<?> e : emf.getMetamodel().getEntities()) {
        if (e.getName().equals(name)) return true;
    }
    return false;
}

// validate every from-clause root before creating the query
if (!isMappedEntityName(emf, rootName)) throw new IllegalArgumentException("Entity not mapped: " + rootName);

Type guard

static boolean isUnknownEntity(Throwable t) {
    return t instanceof org.hibernate.query.sqm.UnknownEntityException;
}

Try / catch

try {
    return em.createQuery(hql, Object[].class).getResultList();
} catch (org.hibernate.query.sqm.UnknownEntityException e) {
    throw new IllegalArgumentException("From-clause root is not a mapped entity: " + e.getEntityName()
            + " - accepted names are in em.getMetamodel().getEntities()", e);
}

Prevention

When it happens

Trigger: 'select e from EMPLOYEE e' where the mapped name is 'Employee'; wrong case; quoted-identifier mismatch; entity missing from the persistence unit; a CTE referenced under a different name than declared in the WITH clause.

Common situations: Native SQL habits (table names instead of entity names); class renamed or moved without updating queries; persistence.xml/persistenceUnitRoot/packagesToScan missing the entity package; case-sensitive mismatches after moving between databases or naming strategies.

Related errors


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