hibernate/hibernate-orm · error · AnnotationException

Column mappings for property '${propertyName}' mix updatable

Error message

Column mappings for property '${propertyName}' mix updatable with 'updatable=false'

What it means

Hibernate throws this at bootstrap while binding a property that maps to multiple columns (e.g. via @Columns, @JoinColumn + @Column, or overridden mappings). Every column mapping belonging to one property must agree on nullability, insertability, updatability, and secondary table; here two of them disagree on the 'updatable' flag, so Hibernate cannot decide what the UPDATE statements should include.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumns.java:174

	public void checkPropertyConsistency() {
		if ( columns.size() > 1 ) {
			for ( int currentIndex = 1; currentIndex < columns.size(); currentIndex++ ) {
				final AnnotatedColumn current = columns.get( currentIndex );
				final AnnotatedColumn previous = columns.get( currentIndex - 1 );
				if ( !current.isFormula() && !previous.isFormula() ) {
					if ( current.isNullable() != previous.isNullable() ) {
						throw new AnnotationException(
								"Column mappings for property '" + propertyName + "' mix nullable with 'not null'"
						);
					}
					if ( current.isInsertable() != previous.isInsertable() ) {
						throw new AnnotationException(
								"Column mappings for property '" + propertyName + "' mix insertable with 'insertable=false'"
						);
					}
					if ( current.isUpdatable() != previous.isUpdatable() ) {
						throw new AnnotationException(
								"Column mappings for property '" + propertyName + "' mix updatable with 'updatable=false'"
						);
					}
					if ( !current.getExplicitTableName().equals( previous.getExplicitTableName() ) ) {
						throw new AnnotationException(
								"Column mappings for property '" + propertyName + "' mix distinct secondary tables"
						);
					}
				}
			}
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Find the property named in the message and set the SAME 'updatable' value on every @Column/@JoinColumn that maps it (default is true).
  2. Check @AttributeOverride / @AssociationOverride declarations in subclasses and embeddings for flags that differ from the parent mapping; make them consistent.
  3. If one column really must be read-only while others are writable, split them into two properties (one with updatable=false) instead of one property with mixed flags.

Example fix

// before
@Entity
class Person {
    @Columns({
        @Column(name = "first_name"),
        @Column(name = "last_name", updatable = false) // mixed flags
    })
    private Name name;
}

// after
@Entity
class Person {
    @Columns({
        @Column(name = "first_name"),
        @Column(name = "last_name") // consistent: both updatable
    })
    private Name name;
}
Defensive patterns

Strategy: validation

Validate before calling

// Startup self-check: fail with a clear report before Hibernate binds
for (Class<?> cls : persistenceUnitClasses) {
    for (Field f : cls.getDeclaredFields()) {
        Column[] cols = f.getAnnotationsByType(Column.class);
        Set<Boolean> upd = Arrays.stream(cols).map(Column::updatable).collect(toSet());
        if (cols.length > 1 && upd.size() > 1) {
            throw new IllegalStateException(cls.getSimpleName() + "." + f.getName()
                + " mixes updatable flags across " + cols.length + " columns");
        }
    }
}

Try / catch

try {
    Metadata metadata = metadataBuilder.build(); // binding happens here
} catch (AnnotationException e) {
    // message names the property: "Column mappings for property 'x' mix updatable..."
    throw newConfigurationException("Inconsistent column flags", e);
}

Prevention

When it happens

Trigger: A property carries two column mappings where one is 'updatable=true' (the default) and the other is '@Column(..., updatable=false)'. Typical shapes: an @AttributeOverride/@AssociationOverride in a subclass that flips updatable on one column of a multi-column property; a @Column plus a @JoinColumn (or @JoinColumns) on the same association with mismatched flags; the same property mapped twice through an embedded and an override.

Common situations: Copying a read-only pattern ('insertable=false, updatable=false') onto only the first of several @Column entries of a property; overriding an embedded or mapped-superclass mapping in a subclass without repeating all flags; mixing JPA annotations with legacy XML hbm mappings where one side sets updatable=false.

Related errors


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