hibernate/hibernate-orm · error · MappingException

Ambiguous persistent property methods declared by '%s': '%s'

Error message

Ambiguous persistent property methods declared by '%s': '%s' and '%s' (mark one '@Transient')

What it means

During attribute discovery PropertyContainer collects property accessors; when two method-backed candidates resolve to the same persistent property name, throwAmbiguousPropertyException throws a MappingException naming both methods, with Origin(ANNOTATION, className). Hibernate cannot pick which accessor defines the property, so it demands you disambiguate with @Transient.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyContainer.java:204

				persistentAttributesFromGetters.put( name, getterDetails );
			}

		}

		// Check record components...
		for ( int i = 0; i < recordComponents.size(); i++ ) {
			final var recordComponentDetails = recordComponents.get( i );
			if ( recordComponentDetails.hasDirectAnnotationUsage( Access.class ) ) {
				final String name = recordComponentDetails.getName();
				persistentAttributeMap.put( name, recordComponentDetails );
				persistentAttributesFromComponents.put( name, recordComponentDetails );
			}
		}
	}

	private static void throwAmbiguousPropertyException(
			ClassDetails classDetails, MethodDetails previous, MethodDetails getterDetails) {
		throw new MappingException(
				String.format(
						"Ambiguous persistent property methods declared by '%s': '%s' and '%s' (mark one '@Transient')",
						classDetails.getName(),
						previous.getName(),
						getterDetails.getName()
				),
				new Origin( SourceType.ANNOTATION, classDetails.getName() )
		);
	}

	/**
	 * Collects members "backing" an attribute based on the Class's "default" access-type
	 */
	private static void collectPersistentAttributesUsingClassLevelAccessType(
			ClassDetails classDetails,
			AccessType classLevelAccessType,
			Map<String, MemberDetails> persistentAttributeMap,
			Map<String,MethodDetails> persistentAttributesFromGetters,

View on GitHub (pinned to fad1729dce)

Solutions

  1. Mark one of the two methods @Transient so only the other is persistent.
  2. Delete the duplicate accessor and keep a single canonical form (isX for primitive boolean, getX otherwise).
  3. Rename one method if both must stay on the API but only one is persistent.
  4. Check for generated code (Lombok/IDE) re-adding the removed accessor and exclude it.

Example fix

// before
public class Order {
    public boolean isPaid() { return paid; }
    public Boolean getPaid() { return paid; } // ambiguous
}

// after
public class Order {
    public boolean isPaid() { return paid; }

    @Transient
    public Boolean getPaid() { return paid; } // not persistent
}
Defensive patterns

Strategy: validation

Validate before calling

// scan mapped classes for duplicate property accessors before bootstrap
for (PropertyDescriptor pd : Introspector.getBeanInfo(Order.class).getPropertyDescriptors()) {
    Method read = pd.getReadMethod();
    if (read != null && hasConflictingAccessor(Order.class, pd.getName(), read)) {
        throw new IllegalStateException("Ambiguous accessors for property " + pd.getName());
    }
}

Try / catch

try {
    metadata = sources.buildMetadata();
} catch (MappingException e) { // ambiguous-property MappingException carries Origin(ANNOTATION, class)
    failBuild("Duplicate accessors in " + e.getOrigin() + ": " + e.getMessage());
}

Prevention

When it happens

Trigger: A class exposes two getter forms for one property, e.g. boolean isFlag() plus Boolean getFlag(); or an overloaded getter pair; or a getter contributed twice via class + implemented interface so both MethodDetails survive collection. Raised while the PropertyContainer is built for the annotated class.

Common situations: Lombok @Getter on a boolean generating isX() while a hand-written getX() also exists (or vice versa); IDE auto-generating the second accessor form; interfaces declaring getters that classes redeclare; refactoring boolean wrappers without deleting the old accessor.

Related errors


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