hibernate/hibernate-orm · error · MappingException
map index element must specify a type: %s
Error message
map index element must specify a type: %s
What it means
For a <map> with a basic (non-entity, non-composite) index, Hibernate builds a BasicValue for the map key from <map-key>. There is no backing Java property to reflect on, so if after binding the type information value.isTypeSpecified() is false - no type= on <map-key> and nothing inferable - the key column's type is unknown and binding fails.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java:3699
componentBinding,
null,
pluralAttributeSource.getName(),
false
);
collectionBinding.setIndex( componentBinding );
}
private void bindBasicMapKey(
MappingDocument mappingDocument,
IndexedPluralAttributeSource pluralAttributeSource,
org.hibernate.mapping.Map collectionBinding,
PluralAttributeMapKeySourceBasic mapKeySource) {
final var value =
new BasicValue( mappingDocument,
collectionBinding.getCollectionTable() );
bindSimpleValueType( mappingDocument, mapKeySource.getTypeInformation(), value );
if ( !value.isTypeSpecified() ) {
throw new MappingException(
"map index element must specify a type: "
+ pluralAttributeSource.getAttributeRole().getFullPath(),
mappingDocument.getOrigin()
);
}
relationalObjectBinder.bindColumnsAndFormulas(
mappingDocument,
mapKeySource.getRelationalValueSources(),
value,
true,
context -> database.toIdentifier( IndexedCollection.DEFAULT_INDEX_COLUMN_NAME )
);
collectionBinding.setIndex( value );
}
private class ManyToOneColumnBinder implements ImplicitColumnNamingSecondPass {View on GitHub (pinned to fad1729dce)
Solutions
- Add the needed type to the <map-key> element, e.g. <map-key column='lang' type='string'/>
- For composite keys use <composite-map-key class='...'> and for entity keys use <map-key-many-to-many class='...'> instead of a typed basic <map-key>
Example fix
// before
<map name='labels' table='labels'>
<key column='item_id'/>
<map-key column='lang'/>
<element column='text' type='string'/>
</map>
// after
<map name='labels' table='labels'>
<key column='item_id'/>
<map-key column='lang' type='string'/>
<element column='text' type='string'/>
</map> Defensive patterns
Strategy: validation
Validate before calling
NodeList maps = doc.getElementsByTagName("map");
for (int i = 0; i < maps.getLength(); i++) {
Element map = (Element) maps.item(i);
NodeList keys = map.getElementsByTagName("map-key");
for (int j = 0; j < keys.getLength(); j++) {
Element k = (Element) keys.item(j);
if (k.getAttributeNode("type") == null || k.getAttribute("type").isBlank()) {
throw new IllegalStateException("<map-key> of " + map.getAttribute("name") + " must declare a type");
}
}
} Try / catch
catch (MappingException e) at bootstrap; the message names the map's attribute role. Add the matching type attribute to that <map-key> and rebuild.
Prevention
- Always set type= on basic <map-key> elements
- Use <composite-map-key> or <map-key-many-to-many> for non-basic keys
- When converting <set> to <map>, remember the index needs an explicit type
When it happens
Trigger: <map><key .../><map-key column='lang'/><element .../></map> - a <map-key> element without a type attribute; also a map-key whose type attribute name is unresolvable so isTypeSpecified() ends up false.
Common situations: Converting a <set> to a <map> and forgetting the key type; assuming Hibernate guesses the index type like it can for POJO <id> properties (it cannot - a map key has no property to reflect on).
Related errors
- Collection '{}' is annotated both '@MapKey' and '@MapKeyColu
- filter alias must define either table or entity attribute
- must specify an identifier type: %s
- Attribute [%s] referenced columns from multiple tables: %s,
- many-to-one attribute [%s] specified delete-orphan but is no
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/81d5d4f9c0462f7c.
Report an issue: GitHub.