hibernate/hibernate-orm · error · MappingException
Non-terminal property path did not reference FetchableContai
Error message
Non-terminal property path did not reference FetchableContainer: " + navigablePath
What it means
When resolving a @FieldResult name that contains multiple dot-separated parts, SqlResultSetMappingDescriptor walks the entity metamodel part by part. Each intermediate part must resolve to a ModelPartContainer (an embeddable, association, or collection) so the walk can continue; when an intermediate part is a basic attribute, the remaining parts have nowhere to go and this MappingException is thrown with the NavigablePath reached so far. It is the annotation-side twin of error 749.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java:448
// }
@Nonnull
@Override
public FetchMemento resolve(@Nonnull ResultSetMappingResolutionContext resolutionContext) {
final var entityMapping =
resolutionContext.getMappingMetamodel()
.getEntityDescriptor( entityName );
final String rootPropertyPathPart = propertyPathParts[0];
var subPart = entityMapping.findSubPart( rootPropertyPathPart, null );
var navigablePath = rootNavigablePath( subPart, entityMapping, rootPropertyPathPart );
for ( int i = 1; i < propertyPathParts.length; i++ ) {
if ( subPart instanceof ModelPartContainer modelPartContainer ) {
final String propertyPathPart = propertyPathParts[i];
navigablePath = navigablePath.append( propertyPathPart );
subPart = modelPartContainer.findSubPart( propertyPathPart, null );
}
else {
throw new MappingException(
"Non-terminal property path did not reference FetchableContainer: "
+ navigablePath
);
}
}
return getFetchMemento( navigablePath, subPart );
}
private NavigablePath rootNavigablePath(
@Nonnull ModelPart parentSubPart,
@Nonnull EntityPersister entityMapping,
@Nonnull String rootPropertyPathPart) {
final var parentNavigableRole = parentSubPart.getNavigableRole().getParent();
final var parentNavigablePath =
!Objects.equals( parentNavigableRole, entityMapping.getNavigableRole() )
&& parentNavigableRole.getLocalName().equals( ID_ROLE_NAME )
// The attribute is defined in an ID class, append {id} to navigable path
? new EntityIdentifierNavigablePath( this.navigablePath, null )View on GitHub (pinned to fad1729dce)
Solutions
- Shorten the path to end at the basic attribute: @FieldResult(name = "address.zip", column = "ZIP").
- If nesting is intended, make the intermediate attribute an @Embeddable/component so it is a ModelPartContainer.
- Verify each intermediate segment against the entity's current mapped structure and fix stale names.
Example fix
// before: 'address.zip' is a basic String @FieldResult(name = "address.zip.code", column = "ZIP") // after @FieldResult(name = "address.zip", column = "ZIP")
Defensive patterns
Strategy: validation
Validate before calling
// validate a dotted @FieldResult name against the metamodel before creating the EMF:
ManagedDomainType<?> t = metamodel.entity( entityClass );
String[] parts = fieldResult.name().split( "\\." );
for ( int i = 0; i < parts.length; i++ ) {
Attribute<?, ?> attr = (Attribute<?, ?>) ( (ManagedDomainType<?>) t ).getAttribute( parts[i] );
if ( attr == null ) throw new IllegalStateException( "Unknown segment '" + parts[i] + "' in " + fieldResult.name() );
if ( i < parts.length - 1 && ! ( attr.getPersistentAttributeType() == PersistentAttributeType.EMBEDDED
|| attr.getPersistentAttributeType() == PersistentAttributeType.ELEMENT_COLLECTION
|| attr.getPersistentAttributeType() == PersistentAttributeType.MANY_TO_ONE
|| attr.getPersistentAttributeType() == PersistentAttributeType.ONE_TO_ONE ) ) {
throw new IllegalStateException( "Segment '" + parts[i] + "' is basic; path too deep: " + fieldResult.name() );
}
if ( i < parts.length - 1 ) t = metamodel.embeddable( attr.getJavaType() );
} Try / catch
catch ( MappingException e ) {
if ( e.getMessage().startsWith( "Non-terminal property path did not reference FetchableContainer" ) ) {
// shorten the @FieldResult name to end at the basic attribute, or model the middle segment as an embeddable
}
} Prevention
- Keep @FieldResult names in lockstep with the entity's component structure; update both when refactoring embeddables.
- Smoke-test native queries with @SqlResultSetMapping in CI so structural drift is caught at build time.
When it happens
Trigger: @FieldResult(name = "address.zip.code", column = "ZIP") where 'address.zip' is a plain String; a dotted path left over from when the attribute was an embeddable and is now basic; paths copied from another entity with a deeper component structure.
Common situations: Refactoring an embeddable into basic columns (or vice versa) without updating @SqlResultSetMapping; entity-specific mappings reused across similar entities; typos that make an intermediate segment resolve to a basic attribute.
Related errors
- Passed FieldResult [%s, %s] does not match AttributeFetchMap
- ConstructorResult did not define any ColumnResults
- Unknown attribute: {}
- Expecting Component for id mapping with no id-attribute
- {mappedSuperclassTypeName} is not a supertype of {componentT
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/bcfe495440fbe669.
Report an issue: GitHub.