hibernate/hibernate-orm · critical · MappingException
must be an BeforeExecutionGenerator
Error message
must be an BeforeExecutionGenerator
What it means
For an identified collection (idbag), AbstractCollectionPersister.createGenerator builds the identifier generator for the collection-row id and requires it to be a BeforeExecutionGenerator (value available before the INSERT executes). If generator.generatedOnExecution() is true — identity/native/trigger-style generation — Hibernate throws MappingException('must be an BeforeExecutionGenerator') (the message typo is acknowledged with a TODO in Hibernate's source).
Source
Thrown at hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java:688
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;
}
private boolean shouldUseShallowCacheLayout(CacheLayout collectionQueryCacheLayout, SessionFactoryOptions options) {
final var queryCacheLayout =
collectionQueryCacheLayout == null
? options.getQueryCacheLayout()
: collectionQueryCacheLayout;
return queryCacheLayout == CacheLayout.SHALLOW
|| queryCacheLayout == CacheLayout.AUTO && cacheAccessStrategy != null;
}
@Override
public NavigableRole getNavigableRole() {
return navigableRole;
}
View on GitHub (pinned to fad1729dce)
Solutions
- Switch the @CollectionId generator to a before-execution strategy: sequence, increment, uuid, guid, hilo, or a table generator
- If you cannot pre-generate ids, drop @CollectionId and use a plain bag (row identity via the key + element columns)
- Model the rows as an explicit @Entity with its own id when database identity assignment is a hard requirement
Example fix
// before @CollectionId( columns = @Column(name = "line_id"), generator = "native", // identity-style -> MappingException type = Long.class) private List<String> tags; // after @GenericGenerator(name = "seq", strategy = "sequence", parameters = @Parameter(name = "sequence_name", value = "tag_seq")) @CollectionId( columns = @Column(name = "line_id"), generator = "seq", // before-execution -> OK type = Long.class) private List<String> tags;
Defensive patterns
Strategy: validation
Validate before calling
// Startup scan: @CollectionId must not use an execute-time generator (identity/native)
for (Class<?> c : scannedEntityClasses) {
for (java.lang.reflect.Field f : c.getDeclaredFields()) {
org.hibernate.annotations.CollectionId cid =
f.getAnnotation(org.hibernate.annotations.CollectionId.class);
if (cid != null) {
org.hibernate.annotations.GenericGenerator g = f.getAnnotation(org.hibernate.annotations.GenericGenerator.class);
String strategy = g != null ? g.strategy() : cid.generator();
if (strategy.equals("identity") || strategy.equals("native") || strategy.equals("trigger")) {
throw new IllegalStateException("@CollectionId on " + f + " uses execute-time generator '" + strategy
+ "'; idbags need a before-execution generator (sequence/increment/uuid/uuid2/table/hilo)");
}
}
}
} Try / catch
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (MappingException e) {
if (e.getMessage() != null && e.getMessage().contains("must be an BeforeExecutionGenerator")) {
throw new IllegalStateException("Collection id generator must be before-execution (sequence/increment/uuid), not identity/native", e);
}
throw e;
} Prevention
- Never reuse entity PK identity strategies ('native'/'identity') for @CollectionId generators
- Standardize a named sequence or uuid2 generator for all idbag collection ids in your project
- Cover mapping bootstrap with a buildSessionFactory smoke test in CI
When it happens
Trigger: @CollectionId combined with a database-identity generator: @GenericGenerator(strategy="native") or "identity" on the @CollectionId, or hbm.xml <collection-id><generator class="native"/></collection-id>; a custom PostInsertGenerator-style generator registered for the collection id.
Common situations: Teams reuse their entity ID strategy ('native' for autoincrement PKs) on @CollectionId; migrating HBM idbags that worked on older dialects; MySQL/SQLServer users where identity is the default everywhere.
Related errors
- one-to-many collections with identifiers are not supported
- Generator '%s' declares generated type '%s', which is not as
- Unknown collection: {}
- Could not resolve named query '{}' for loading collection '{
- The {storageEngine} storage engine is not supported
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/1a5d5198122dee86.
Report an issue: GitHub.