hibernate/hibernate-orm · error · MappingException
Non-terminal property path did not reference FetchableContai
Error message
Non-terminal property path did not reference FetchableContainer - %s
What it means
When a return-property path is resolved against the runtime metamodel, Hibernate walks it part by part: after the first part it requires the current Fetchable to also be a FetchableContainer (an embeddable, association, or collection) before descending to the next part. If an intermediate part resolves to a basic-valued attribute, there is nothing to descend into and this MappingException is thrown with the NavigablePath reached so far.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java:659
@Override
public FetchMemento resolve(@Nonnull ResultSetMappingResolutionContext resolutionContext) {
BootQueryLogging.BOOT_QUERY_LOGGER.tracef(
"Resolving HBM PropertyFetchDescriptor into memento - %s : %s",
parent,
propertyPath
);
final FetchParentMemento fetchParentMemento = parent.resolveParentMemento( resolutionContext );
Fetchable fetchable = (Fetchable) fetchParentMemento.getFetchableContainer().findSubPart(
propertyPathParts[ 0 ],
null
);
NavigablePath navigablePath = fetchParentMemento.getNavigablePath().append( fetchable.getFetchableName() );
for ( int i = 1; i < propertyPathParts.length; i++ ) {
if ( ! ( fetchable instanceof FetchableContainer ) ) {
throw new MappingException(
String.format(
Locale.ROOT,
"Non-terminal property path did not reference FetchableContainer - %s ",
navigablePath
)
);
}
fetchable = (Fetchable) ( (FetchableContainer) fetchable.getPartMappingType() ).findSubPart( propertyPathParts[i], null );
navigablePath = navigablePath.append( fetchable.getFetchableName() );
}
final BasicValuedModelPart basicPart = fetchable.asBasicValuedModelPart();
if ( basicPart != null ) {
return new FetchMementoBasicStandard(
navigablePath,
basicPart,
columnAliases.get( 0 )
);View on GitHub (pinned to fad1729dce)
Solutions
- Shorten the path so it ends at the basic attribute: 'address.zip'.
- If the target really is nested, make the intermediate segment a true embeddable (@Embeddable/<component>) so it is a FetchableContainer.
- Re-check the property structure of the entity with the metamodel or the mapping document and align the path to it.
Example fix
<!-- before: 'address.zip' is a basic String, cannot descend to '.code' --> <return-property name="address.zip.code" column="ZIP"/> <!-- after --> <return-property name="address.zip" column="ZIP"/>
Defensive patterns
Strategy: validation
Validate before calling
// pre-check a dotted return-property path: every non-final segment must be an embeddable/association
SqmPathSource<?> current = (SqmPathSource<?>) entityType.getAttributes().stream()
.filter( a -> a.getName().equals( parts[0] ) ).findFirst().orElseThrow();
for ( int i = 1; i < parts.length - 1; i++ ) {
if ( ! ( current.getSqmPathType() instanceof EmbeddableTypeImpl || current.isAssociation() ) ) {
throw new IllegalStateException( "Segment '" + parts[i-1] + "' is basic; cannot descend to " + propertyPath );
}
current = (SqmPathSource<?>) ( (ManagedDomainType<?>) current.getSqmPathType() ).getAttribute( parts[i] );
} Try / catch
catch ( MappingException e ) {
if ( e.getMessage().startsWith( "Non-terminal property path" ) ) {
// trim the path to the last basic attribute, or model the intermediate as an embeddable
}
} Prevention
- Validate dotted paths against the current domain model in a boot test whenever entity structure changes.
- Refactor embeddables into basic columns (or back) only together with the native query mappings that use them.
When it happens
Trigger: A return-property name like 'address.zip.code' where 'address.zip' is a plain String; a path that keeps appending segments after a terminal basic attribute; treating a basic column as if it were an embedded component.
Common situations: An embeddable was flattened into basic columns during refactoring while the native query mapping kept the long dotted path; porting mappings between entities whose component structure differs.
Related errors
- property [" + element + "] not found on collection [" + coll
- property [" + propertyPath + "] not found on entity [" + ent
- Cannot combine other returns with a collection return (" + r
- Illegal <return-join/> property attribute: '" + fullProperty
- Property join specified twice for join-return '" + ownerTabl
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/18d693e91595f9d0.
Report an issue: GitHub.