hibernate/hibernate-orm · critical · MappingException

Unable to resolve mapped-by path

Error message

Unable to resolve mapped-by path : (%s) %s

What it means

AbstractCollectionPersister resolves a mappedBy property path by walking the target entity's attribute mappings token-by-token (source.findAttributeMapping(partName), descending through ManagedMappingType). If a segment is missing or an intermediate segment is not a managed type, resolution fails with MappingException naming the entity and the full mappedBy path.

Solutions

  1. Verify the mappedBy property exists verbatim on the referenced entity class (check spelling and get/set pairs)
  2. For dotted paths, check each segment: intermediate segments must be embeddable-valued attributes, final segment is the mapped attribute
  3. Ensure mappedBy is on the inverse (non-owning) side and matches the owning side's @JoinColumn/property
  4. After refactors, grep for mappedBy values and keep them in sync with the renamed property

Example fix

// before
@Entity public class Order {
  @OneToMany(mappedBy = "cust") // no property 'cust' on Customer
  private List<OrderLine> lines;
}

// after
@Entity public class Order {
  @OneToMany(mappedBy = "order") // exact property on OrderLine
  private List<OrderLine> lines;
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify every mappedBy string resolves on the target entity (supports dotted embeddable paths)
static void checkMappedBy(Class<?> targetEntity, String mappedBy) throws Exception {
  Class<?> current = targetEntity;
  String[] parts = mappedBy.split("\\.");
  for (int i = 0; i < parts.length; i++) {
    java.lang.reflect.Field f = Stream.of(current.getDeclaredFields())
        .filter(x -> x.getName().equals(parts[i])).findFirst()
        .orElseThrow(() -> new IllegalStateException(
            "mappedBy '" + mappedBy + "': no property '" + parts[i] + "' on " + current.getName()));
    current = f.getType(); // intermediate segments must be embeddable-valued in the real mapping
  }
}

Try / catch

try {
  sessionFactory = new Configuration().addAnnotatedClass(Customer.class).buildSessionFactory();
} catch (MappingException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Unable to resolve mapped-by path")) {
    throw new IllegalStateException("A mappedBy value points at a nonexistent property — verify the inverse-side attribute name", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: @OneToMany(mappedBy="x") / @ManyToMany(mappedBy="x") where property x does not exist on the referenced entity; a dotted mappedBy path ('address.city') whose intermediate segment is an embeddable attribute that does not exist or is not embeddable; the path's first token does not match any attribute mapping.

Common situations: Rename refactors of the inverse-side property leave mappedBy strings stale; mappedBy copy-pasted from the other side of the association (pointing at itself); dotted paths into @Embedded targets with segments in the wrong order; mappedBy placed on the owning side instead of the inverse side.

Related errors


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

Appendix: source

Thrown at hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java:672

	private static AttributeMapping resolveMappedBy(EntityPersister entityPersister, String mappedByProperty) {
		final var propertyPathParts = new StringTokenizer( mappedByProperty, ".", false );
		final int tokenCount = propertyPathParts.countTokens();
		assert tokenCount > 0;
		if ( tokenCount == 1 ) {
			return entityPersister.findAttributeMapping( propertyPathParts.nextToken() );
		}
		else {
			ManagedMappingType source = entityPersister;
			while ( propertyPathParts.hasMoreTokens() ) {
				final String partName = propertyPathParts.nextToken();
				final var namedPart = source.findAttributeMapping( partName );
				if ( !propertyPathParts.hasMoreTokens() ) {
					return namedPart;
				}
				source = (ManagedMappingType) namedPart.getPartMappingType();
			}
			throw new MappingException(
					String.format(
							Locale.ROOT,
							"Unable to resolve mapped-by path : (%s) %s",
							entityPersister.getEntityName(),
							mappedByProperty
					)
			);
		}
	}

	private BeforeExecutionGenerator createGenerator(RuntimeModelCreationContext context, IdentifierCollection collection) {
		final Generator generator =
				collection.getIdentifier()
						.createGenerator( context.getDialect(), null, null, context.getGeneratorSettings() );
		if ( generator.generatedOnExecution() ) {
			throw new MappingException("must be an BeforeExecutionGenerator"); //TODO fix message
		}
		return (BeforeExecutionGenerator) generator;

View on GitHub (pinned to fad1729dce)