hibernate/hibernate-orm · error · MappingException

Property join specified twice for join-return '" + ownerTabl

Error message

Property join specified twice for join-return '" + ownerTableAlias + "." + propertyPath + "' (" + registrationName + ")

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java:184

					"Illegal <return-join/> property attribute: '" + fullPropertyPath + "' - "
					+ " - should be in the form '{ownerAlias.joinedPropertyPath}' (" + registrationName + ")"
			);
		}

		final String ownerTableAlias = fullPropertyPath.substring( 0, firstDot );
		final String propertyPath = fullPropertyPath.substring( firstDot + 1 );
		final String tableAlias = jaxbHbmJoin.getAlias();

		Map<String, JoinDescriptor> joinDescriptorsForAlias = joinDescriptors.get( ownerTableAlias );
		//noinspection Java8MapApi
		if ( joinDescriptorsForAlias == null ) {
			joinDescriptorsForAlias = new HashMap<>();
			joinDescriptors.put( ownerTableAlias, joinDescriptorsForAlias );
		}

		final JoinDescriptor existing = joinDescriptorsForAlias.get( propertyPath );
		if ( existing != null ) {
			throw new MappingException(
					"Property join specified twice for join-return '" + ownerTableAlias + "." + propertyPath
							+ "' (" + registrationName + ")"
			);
		}

		final JoinDescriptor joinDescriptor = new JoinDescriptor(
				jaxbHbmJoin,
				() -> joinDescriptors,
				() -> fetchParentByAlias,
				registrationName,
				context
		);
		joinDescriptorsForAlias.put( propertyPath, joinDescriptor );
		fetchParentByAlias.put( tableAlias, joinDescriptor );
	}


	/**

View on GitHub (pinned to fad1729dce)

Solutions

  1. Delete the duplicate <return-join/> so each (ownerAlias, propertyPath) appears exactly once.
  2. 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.
  3. Give genuinely different joins different property paths (e.g. o.billingAddress vs o.shippingAddress).

Example fix

<!-- before: same join declared twice -->
<return-join alias="a1" property="o.address"/>
<return-join alias="a2" property="o.address"/>

<!-- after: one join, extra columns via return-property -->
<return-join alias="a1" property="o.address">
    <return-property name="street" column="STREET"/>
    <return-property name="city" column="CITY"/>
</return-join>
Defensive patterns

Strategy: validation

Validate before calling

// detect duplicate joins while pre-parsing the mapping:
Set<String> seen = new HashSet<>();
for ( Element join : returnJoinElements ) {
    String key = join.attributeValue( "property" ); // ownerAlias.propertyPath
    if ( !seen.add( key ) ) {
        throw new IllegalStateException( "Duplicate return-join for " + key );
    }
}

Try / catch

catch ( MappingException e ) {
    if ( e.getMessage().startsWith( "Property join specified twice" ) ) {
        // message contains ownerAlias.propertyPath and the mapping name; dedupe that join
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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