{"record":{"id":"66e3f3c73563728e","repo":"hibernate/hibernate-orm","slug":"property-join-specified-twice-for-join-return","errorCode":null,"errorMessage":"Property join specified twice for join-return '\" + ownerTableAlias + \".\" + propertyPath + \"' (\" + registrationName + \")","messagePattern":"Property join specified twice for join-return '\" \\+ ownerTableAlias \\+ \"\\.\" \\+ propertyPath \\+ \"' \\(\" \\+ registrationName \\+ \"\\)","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java","lineNumber":184,"sourceCode":"\t\t\t\t\t\"Illegal <return-join/> property attribute: '\" + fullPropertyPath + \"' - \"\n\t\t\t\t\t+ \" - should be in the form '{ownerAlias.joinedPropertyPath}' (\" + registrationName + \")\"\n\t\t\t);\n\t\t}\n\n\t\tfinal String ownerTableAlias = fullPropertyPath.substring( 0, firstDot );\n\t\tfinal String propertyPath = fullPropertyPath.substring( firstDot + 1 );\n\t\tfinal String tableAlias = jaxbHbmJoin.getAlias();\n\n\t\tMap<String, JoinDescriptor> joinDescriptorsForAlias = joinDescriptors.get( ownerTableAlias );\n\t\t//noinspection Java8MapApi\n\t\tif ( joinDescriptorsForAlias == null ) {\n\t\t\tjoinDescriptorsForAlias = new HashMap<>();\n\t\t\tjoinDescriptors.put( ownerTableAlias, joinDescriptorsForAlias );\n\t\t}\n\n\t\tfinal JoinDescriptor existing = joinDescriptorsForAlias.get( propertyPath );\n\t\tif ( existing != null ) {\n\t\t\tthrow new MappingException(\n\t\t\t\t\t\"Property join specified twice for join-return '\" + ownerTableAlias + \".\" + propertyPath\n\t\t\t\t\t\t\t+ \"' (\" + registrationName + \")\"\n\t\t\t);\n\t\t}\n\n\t\tfinal JoinDescriptor joinDescriptor = new JoinDescriptor(\n\t\t\t\tjaxbHbmJoin,\n\t\t\t\t() -> joinDescriptors,\n\t\t\t\t() -> fetchParentByAlias,\n\t\t\t\tregistrationName,\n\t\t\t\tcontext\n\t\t);\n\t\tjoinDescriptorsForAlias.put( propertyPath, joinDescriptor );\n\t\tfetchParentByAlias.put( tableAlias, joinDescriptor );\n\t}\n\n\n\t/**","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java#L166-L202","documentation":"Hibernate stores join fetch descriptors per owner alias in a map keyed by property path. When a second <return-join/> resolves to the same (ownerTableAlias, propertyPath) pair, a JoinDescriptor already exists in that map and this MappingException is thrown. The mapping declares the same join twice, which Hibernate cannot disambiguate.","triggerScenarios":"Two <return-join/> elements with the same property attribute (e.g. property=\"o.items\" twice, possibly with different aliases); a copy-pasted join block left in place after adding a new one.","commonSituations":"Mapping files merged during team development where both authors added the same join; legacy mappings where additional columns for one join were expressed as a second identical join instead of nested <return-property/> elements.","solutions":["Delete the duplicate <return-join/> so each (ownerAlias, propertyPath) appears exactly once.","If you needed the second join to map extra columns of the same association, keep one <return-join/> and add the extra columns as <return-property name=\"...\" column=\"...\"/> children of it.","Give genuinely different joins different property paths (e.g. o.billingAddress vs o.shippingAddress)."],"exampleFix":"<!-- before: same join declared twice -->\n<return-join alias=\"a1\" property=\"o.address\"/>\n<return-join alias=\"a2\" property=\"o.address\"/>\n\n<!-- after: one join, extra columns via return-property -->\n<return-join alias=\"a1\" property=\"o.address\">\n    <return-property name=\"street\" column=\"STREET\"/>\n    <return-property name=\"city\" column=\"CITY\"/>\n</return-join>","handlingStrategy":"validation","validationCode":"// detect duplicate joins while pre-parsing the mapping:\nSet<String> seen = new HashSet<>();\nfor ( Element join : returnJoinElements ) {\n    String key = join.attributeValue( \"property\" ); // ownerAlias.propertyPath\n    if ( !seen.add( key ) ) {\n        throw new IllegalStateException( \"Duplicate return-join for \" + key );\n    }\n}","typeGuard":null,"tryCatchPattern":"catch ( MappingException e ) {\n    if ( e.getMessage().startsWith( \"Property join specified twice\" ) ) {\n        // message contains ownerAlias.propertyPath and the mapping name; dedupe that join\n    }\n}","preventionTips":["Keep one join per (owner, path); express extra columns via nested <return-property/> elements.","After merging mapping files, search for repeated property= values within one query mapping.","Cover each native query mapping with a boot test."],"tags":["hibernate","hbm-xml","native-query","return-join","duplicate-mapping"],"backgroundTag":"duplicate-mapping-entry","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}