hibernate/hibernate-orm · error · MappingException

CurrentTimestampGeneration requires exactly one column

Error message

CurrentTimestampGeneration requires exactly one column

What it means

Thrown at bootstrap while initializing CurrentTimestampGeneration (@CurrentTimestamp): the generator writes one value per event, so the annotated property must map to exactly one column. The notNull() initialization step enforces this (and also marks the property non-optional and the column NOT NULL). A property mapped to multiple columns fails with this MappingException.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/generator/internal/CurrentTimestampGeneration.java:131

		delegate = getGeneratorDelegate( annotation.source(), context.getType(), context );
		eventTypes = INSERT_AND_UPDATE;
		propertyType = getPropertyType( context );
		version = isVersion( context );
		notNull( context );
	}

	private static boolean isVersion(GeneratorCreationContext context) {
		final var persistentClass = context.getPersistentClass();
		return persistentClass != null
			&& context.getProperty() == persistentClass.getVersion();
	}

	private static void notNull(GeneratorCreationContext context) {
		final var property = context.getProperty();
		property.setOptional( false );
		final var columns = property.getColumns();
		if ( columns.size() != 1 ) {
			throw new MappingException( "CurrentTimestampGeneration requires exactly one column" );
		}
		columns.get( 0 ).setNullable( false );
	}

	private static GeneratorDelegate getGeneratorDelegate(
			SourceType source,
			Type type,
			GeneratorCreationContext context) {
		return getGeneratorDelegate( source, type.getReturnedClass(), context );
	}

	static GeneratorDelegate getGeneratorDelegate(
			SourceType source,
			Class<?> propertyType,
			GeneratorCreationContext context) {
		return switch (source) {
			case DB -> null;
			case VM -> getGeneratorDelegate( propertyType, getBaseClock( context ), getPrecision( context ) );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Map the timestamp attribute to exactly one column — drop @Columns or replace the multi-column UserType with a single-column AttributeConverter or a built-in java.time mapping
  2. If the DB type is exotic, write an AttributeConverter to a single supported column type instead of a multi-column mapping
  3. Remove @CurrentTimestamp and set the value in a @PrePersist/@PreUpdate listener, or use a DB trigger with @Generated
  4. If the same embeddable is reused across tables, check the member's column mapping in each host entity

Example fix

// before — @CurrentTimestamp on a 2-column mapping
@CurrentTimestamp(event = EventType.INSERT)
@Columns({@Column(name = "created_date"), @Column(name = "created_time")})
LocalDateTime createdAt;   // MappingException: requires exactly one column

// after — single column
@CurrentTimestamp(event = EventType.INSERT)
@Column(name = "created_at", nullable = false)
LocalDateTime createdAt;
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast on @CurrentTimestamp members mapped to multiple columns, before booting
static void checkCurrentTimestampMappings(Class<?>... entities) {
    for (Class<?> entity : entities) {
        for (Field f : entity.getDeclaredFields()) {
            if (f.isAnnotationPresent(CurrentTimestamp.class)) {
                Columns cols = f.getAnnotation(Columns.class);
                if (cols != null && cols.columns().length != 1) {
                    throw new IllegalStateException(entity.getSimpleName() + "." + f.getName()
                            + ": @CurrentTimestamp requires a single-column mapping");
                }
            }
        }
    }
}

Prevention

When it happens

Trigger: Annotating a property with @CurrentTimestamp whose mapping occupies more or less than one column: a property with @Columns (multiple @Column entries), a CompositeUserType spanning several columns (e.g. an offset-time or range split across columns), or an embeddable-level timestamp mapped to several columns.

Common situations: java.time or vendor types (TIMESTAMP WITH TIME ZONE split into two columns, TSRANGE) mapped via composite user types; migrating a field from a single-column mapping to a multi-column type while keeping @CurrentTimestamp; imported mappings that combine generated timestamps with @Columns.

Related errors


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