hibernate/hibernate-orm · error · HibernateException
Attribute was not a Map : ${collectionMemberType}
Error message
Attribute was not a Map : ${collectionMemberType} What it means
Hibernate throws this HibernateException while binding metadata, inside AutoApplicableConverterDescriptorStandardImpl.getAutoAppliedConverterDescriptorForMapKey. When a converter with autoApply=true is considered for the KEY of a map-style plural attribute, Hibernate resolves the attribute's actual member type and requires it to be assignable to java.util.Map; if the member resolves to some other type (List, Set, array, a raw type, or a custom collection), the internal invariant is broken and binding fails.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/convert/internal/AutoApplicableConverterDescriptorStandardImpl.java:110
}
@Override
public ConverterDescriptor<?,?> getAutoAppliedConverterDescriptorForMapKey(
MemberDetails memberDetails,
MetadataBuildingContext context) {
final var collectionMemberType = actualMemberType( memberDetails );
final Type keyType;
if ( Map.class.isAssignableFrom( erasedType( collectionMemberType ) ) ) {
final var typeArguments =
typeArguments( Map.class, collectionMemberType );
if ( typeArguments.length == 0 ) {
return null;
}
keyType = typeArguments[0];
}
else {
throw new HibernateException( "Attribute was not a Map : " + collectionMemberType );
}
return isAssignableFrom( linkedConverterDescriptor.getDomainValueResolvedType(),
canonicalizePrimitive( keyType ) )
? linkedConverterDescriptor
: null;
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Declare the plural attribute as Map<KeyType, ValueType> if the map-key converter is intended to apply
- If the attribute is intentionally a List/Set/array, stop the converter from auto-applying to it with @Convert(disableConversion = true) on the attribute or @Converter(autoApply = false)
- Narrow the converter's domain type so it no longer matches the attribute's key type, or register it explicitly with @Convert instead of autoApply
- If the member is a custom collection type, make sure its class ultimately implements java.util.Map when used where a map key is expected
- Report to Hibernate (HHH) if the attribute is a plain Map and it still fails - a resolution bug in auto-apply handling
Example fix
// before: auto-apply converter + non-Map plural attribute
@Converter(autoApply = true)
public class StatusConverter implements AttributeConverter<Status, String> { ... }
@Entity
class Order {
@ElementCollection
private List<Status> statuses = new ArrayList<>(); // triggers map-key resolution internally
}
// after: either use a Map so map-key auto-apply is well-defined
@ElementCollection
private Map<Status, Integer> statusCounts = new HashMap<>();
// ...or exclude the attribute from auto-apply
@Convert(disableConversion = true)
@ElementCollection
private List<Status> statuses = new ArrayList<>(); Defensive patterns
Strategy: type-guard
Validate before calling
// Before boot: every attribute that map-key converter resolution will visit must be a Map
static boolean allPluralMapAttributesAreMaps(Class<?> entity) {
for (Field f : entity.getDeclaredFields()) {
if (f.isAnnotationPresent(ElementCollection.class)
|| f.isAnnotationPresent(OneToMany.class)
|| f.isAnnotationPresent(ManyToMany.class)) {
if (f.isAnnotationPresent(MapKey.class)
|| f.isAnnotationPresent(MapKeyClass.class)
|| f.isAnnotationPresent(MapKeyEnumerated.class)) {
if (!Map.class.isAssignableFrom(f.getType())) return false;
}
}
}
return true;
} Type guard
// Type guard usable on a single suspected field
static boolean isMapAttribute(Field f) {
return Map.class.isAssignableFrom(f.getType());
} Try / catch
try {
sessionFactory = new MetadataSources(registry).addAnnotatedClass(Order.class)
.buildMetadata().buildSessionFactory();
} catch (HibernateException e) { // "Attribute was not a Map" surfaces here
throw new IllegalStateException("Bad plural-attribute shape for auto-apply converter: " + e.getMessage(), e);
} Prevention
- Prefer Map<Key,Value> declarations whenever a converter must apply to keys
- Register converters explicitly with @Convert(converter = ...) instead of autoApply when only a few attributes need them
- Keep an integration test that builds the SessionFactory so mapping errors surface in CI, not production
When it happens
Trigger: A @Converter(autoApply=true) converter is registered (via @Converter, MetadataBuilder.addAttributeConverter, or autoApplyDetection) and Hibernate resolves map-key auto-apply for a plural attribute whose declared/actual type is not java.util.Map, e.g. a List/Set field processed through map-key converter resolution, or a custom collection implementation masking the Map interface.
Common situations: Upgrading Hibernate between 6.x and 7.x where auto-apply resolution for collection keys/elements was reworked; introducing an autoApply converter into a codebase that already uses custom collection types; generics erased by proxying or raw types.
Related errors
- Unable to create AttributeConverter instance
- Unable to build Hibernate SessionFactory [persistence unit:
- Could not resolve PropertyAccess for attribute `%s#%s`
- Could not resolve PropertyAccess for attribute `%s#%s`
- AttributeConverter class [%s] registered multiple times
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/2954b95f1ac4de16.
Report an issue: GitHub.