{"record":{"id":"18d693e91595f9d0","repo":"hibernate/hibernate-orm","slug":"non-terminal-property-path-did-not-reference-fetch","errorCode":null,"errorMessage":"Non-terminal property path did not reference FetchableContainer - %s ","messagePattern":"Non-terminal property path did not reference FetchableContainer - (.+?) ","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java","lineNumber":659,"sourceCode":"\t\t@Override\n\t\tpublic FetchMemento resolve(@Nonnull ResultSetMappingResolutionContext resolutionContext) {\n\t\t\tBootQueryLogging.BOOT_QUERY_LOGGER.tracef(\n\t\t\t\t\t\"Resolving HBM PropertyFetchDescriptor into memento - %s : %s\",\n\t\t\t\t\tparent,\n\t\t\t\t\tpropertyPath\n\t\t\t);\n\n\t\t\tfinal FetchParentMemento fetchParentMemento = parent.resolveParentMemento( resolutionContext );\n\n\t\t\tFetchable fetchable = (Fetchable) fetchParentMemento.getFetchableContainer().findSubPart(\n\t\t\t\t\tpropertyPathParts[ 0 ],\n\t\t\t\t\tnull\n\t\t\t);\n\t\t\tNavigablePath navigablePath = fetchParentMemento.getNavigablePath().append( fetchable.getFetchableName() );\n\n\t\t\tfor ( int i = 1; i < propertyPathParts.length; i++ ) {\n\t\t\t\tif ( ! ( fetchable instanceof FetchableContainer ) ) {\n\t\t\t\t\tthrow new MappingException(\n\t\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\t\t\"Non-terminal property path did not reference FetchableContainer - %s \",\n\t\t\t\t\t\t\t\t\tnavigablePath\n\t\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tfetchable = (Fetchable) ( (FetchableContainer) fetchable.getPartMappingType() ).findSubPart( propertyPathParts[i], null );\n\t\t\t\tnavigablePath = navigablePath.append( fetchable.getFetchableName() );\n\t\t\t}\n\n\t\t\tfinal BasicValuedModelPart basicPart = fetchable.asBasicValuedModelPart();\n\t\t\tif ( basicPart != null ) {\n\t\t\t\treturn new FetchMementoBasicStandard(\n\t\t\t\t\t\tnavigablePath,\n\t\t\t\t\t\tbasicPart,\n\t\t\t\t\t\tcolumnAliases.get( 0 )\n\t\t\t\t);","sourceCodeStart":641,"sourceCodeEnd":677,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java#L641-L677","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"<!-- before: 'address.zip' is a basic String, cannot descend to '.code' -->\n<return-property name=\"address.zip.code\" column=\"ZIP\"/>\n\n<!-- after -->\n<return-property name=\"address.zip\" column=\"ZIP\"/>","handlingStrategy":"validation","validationCode":"// pre-check a dotted return-property path: every non-final segment must be an embeddable/association\nSqmPathSource<?> current = (SqmPathSource<?>) entityType.getAttributes().stream()\n        .filter( a -> a.getName().equals( parts[0] ) ).findFirst().orElseThrow();\nfor ( int i = 1; i < parts.length - 1; i++ ) {\n    if ( ! ( current.getSqmPathType() instanceof EmbeddableTypeImpl || current.isAssociation() ) ) {\n        throw new IllegalStateException( \"Segment '\" + parts[i-1] + \"' is basic; cannot descend to \" + propertyPath );\n    }\n    current = (SqmPathSource<?>) ( (ManagedDomainType<?>) current.getSqmPathType() ).getAttribute( parts[i] );\n}","typeGuard":null,"tryCatchPattern":"catch ( MappingException e ) {\n    if ( e.getMessage().startsWith( \"Non-terminal property path\" ) ) {\n        // trim the path to the last basic attribute, or model the intermediate as an embeddable\n    }\n}","preventionTips":["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."],"tags":["hibernate","hbm-xml","native-query","property-path","metamodel"],"backgroundTag":"non-terminal-property-path","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}