{"record":{"id":"1a5d5198122dee86","repo":"hibernate/hibernate-orm","slug":"must-be-an-beforeexecutiongenerator","errorCode":null,"errorMessage":"must be an BeforeExecutionGenerator","messagePattern":"must be an BeforeExecutionGenerator","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"critical","filePath":"hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java","lineNumber":688,"sourceCode":"\t\t\t\tsource = (ManagedMappingType) namedPart.getPartMappingType();\n\t\t\t}\n\t\t\tthrow new MappingException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\"Unable to resolve mapped-by path : (%s) %s\",\n\t\t\t\t\t\t\tentityPersister.getEntityName(),\n\t\t\t\t\t\t\tmappedByProperty\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate BeforeExecutionGenerator createGenerator(RuntimeModelCreationContext context, IdentifierCollection collection) {\n\t\tfinal Generator generator =\n\t\t\t\tcollection.getIdentifier()\n\t\t\t\t\t\t.createGenerator( context.getDialect(), null, null, context.getGeneratorSettings() );\n\t\tif ( generator.generatedOnExecution() ) {\n\t\t\tthrow new MappingException(\"must be an BeforeExecutionGenerator\"); //TODO fix message\n\t\t}\n\t\treturn (BeforeExecutionGenerator) generator;\n\t}\n\n\tprivate boolean shouldUseShallowCacheLayout(CacheLayout collectionQueryCacheLayout, SessionFactoryOptions options) {\n\t\tfinal var queryCacheLayout =\n\t\t\t\tcollectionQueryCacheLayout == null\n\t\t\t\t\t\t? options.getQueryCacheLayout()\n\t\t\t\t\t\t: collectionQueryCacheLayout;\n\t\treturn queryCacheLayout == CacheLayout.SHALLOW\n\t\t\t|| queryCacheLayout == CacheLayout.AUTO && cacheAccessStrategy != null;\n\t}\n\n\t@Override\n\tpublic NavigableRole getNavigableRole() {\n\t\treturn navigableRole;\n\t}\n","sourceCodeStart":670,"sourceCodeEnd":706,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java#L670-L706","documentation":"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).","triggerScenarios":"@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.","commonSituations":"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.","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"],"exampleFix":"// before\n@CollectionId(\n  columns = @Column(name = \"line_id\"),\n  generator = \"native\", // identity-style -> MappingException\n  type = Long.class)\nprivate List<String> tags;\n\n// after\n@GenericGenerator(name = \"seq\", strategy = \"sequence\",\n  parameters = @Parameter(name = \"sequence_name\", value = \"tag_seq\"))\n@CollectionId(\n  columns = @Column(name = \"line_id\"),\n  generator = \"seq\", // before-execution -> OK\n  type = Long.class)\nprivate List<String> tags;","handlingStrategy":"validation","validationCode":"// Startup scan: @CollectionId must not use an execute-time generator (identity/native)\nfor (Class<?> c : scannedEntityClasses) {\n  for (java.lang.reflect.Field f : c.getDeclaredFields()) {\n    org.hibernate.annotations.CollectionId cid =\n        f.getAnnotation(org.hibernate.annotations.CollectionId.class);\n    if (cid != null) {\n      org.hibernate.annotations.GenericGenerator g = f.getAnnotation(org.hibernate.annotations.GenericGenerator.class);\n      String strategy = g != null ? g.strategy() : cid.generator();\n      if (strategy.equals(\"identity\") || strategy.equals(\"native\") || strategy.equals(\"trigger\")) {\n        throw new IllegalStateException(\"@CollectionId on \" + f + \" uses execute-time generator '\" + strategy\n            + \"'; idbags need a before-execution generator (sequence/increment/uuid/uuid2/table/hilo)\");\n      }\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  sessionFactory = new Configuration().configure().buildSessionFactory();\n} catch (MappingException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"must be an BeforeExecutionGenerator\")) {\n    throw new IllegalStateException(\"Collection id generator must be before-execution (sequence/increment/uuid), not identity/native\", e);\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["hibernate","idbag","id-generation","collection-mapping","bootstrap"],"backgroundTag":"unsupported-id-generator","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}