hibernate/hibernate-orm · error · MappingException

'generated' attribute cannot be 'insert' or 'update' for ver

Error message

'generated' attribute cannot be 'insert' or 'update' for version/timestamp property

What it means

For <version>/<timestamp> properties Hibernate only allows generated='never' (default) or generated='always' (fully DB-generated on both insert and update). INSERT- or UPDATE-timed generation is rejected because the version value must be written on every bump for optimistic locking to stay correct; the DTD disallows it and this binder check enforces it for non-XSD-validated mappings.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java:2248

					columns( property.getValue() ) );
		}
	}

	private String toCascadeString(EnumSet<CascadeType> defaultCascadeTypes) {
		return isEmpty( defaultCascadeTypes ) ? "none" : renderCascadeTypeList( defaultCascadeTypes );
	}

	private static void handleGenerationTiming(
			MappingDocument mappingDocument,
			AttributeSource propertySource,
			Property property,
			GenerationTiming timing) {
		if ( timing != null ) {
			if ( (timing == GenerationTiming.INSERT || timing == GenerationTiming.UPDATE)
					&& property.getValue() instanceof SimpleValue simpleValue
					&& simpleValue.isVersion() ) {
				// this is enforced by DTD, but just make sure
				throw new MappingException(
						"'generated' attribute cannot be 'insert' or 'update' for version/timestamp property",
						mappingDocument.getOrigin()
				);
			}
			if ( timing != GenerationTiming.NEVER ) {
				property.setValueGeneratorCreator( context
						-> new GeneratedGeneration( timing.getEventTypes() ) );

				// generated properties can *never* be insertable...
				if ( property.isInsertable() && timing.includesInsert() ) {
					BOOT_LOGGER.tracef(
							"Property [%s] specified %s generation, setting insertable to false: %s",
							propertySource.getName(),
							timing.name(),
							mappingDocument.getOrigin()
					);
					property.setInsertable( false );
				}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove the generated attribute (default never) from the version/timestamp element
  2. If the DB generates the version on every write, use generated='always' instead
  3. If the column is only insert-generated but is not truly the optimistic-lock version, map it as a plain <property generated='insert'> instead of <version>

Example fix

// before
<version name='ver' column='ver' generated='insert'/>

// after
<version name='ver' column='ver' generated='always'/>
Defensive patterns

Strategy: validation

Validate before calling

NodeList versions = doc.getElementsByTagName("version");
NodeList stamps = doc.getElementsByTagName("timestamp");
BiPredicate<Element, String> bad = (e, attr) -> "insert".equals(e.getAttribute(attr)) || "update".equals(e.getAttribute(attr));
for (int i = 0; i < versions.getLength(); i++) { if (bad.test((Element) versions.item(i), "generated")) throw new IllegalStateException("version generated must be never|always"); }
for (int i = 0; i < stamps.getLength(); i++) { if (bad.test((Element) stamps.item(i), "generated")) throw new IllegalStateException("timestamp generated must be never|always"); }

Try / catch

catch (MappingException e) at bootstrap; remove or change generated= on the flagged <version>/<timestamp> to 'always' or omit it, then rebuild.

Prevention

When it happens

Trigger: <version name='ver' generated='insert'/> or <timestamp name='ts' generated='update'/> in hbm.xml where the value is a SimpleValue flagged as the version.

Common situations: Copying generated attributes from <id> or regular property mappings onto a version column; DB-defaulted version columns misunderstood as partially generated.

Related errors


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