hibernate/hibernate-orm · error · AnnotationException

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

Error message

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

What it means

The insertability leg of AnnotatedColumns.checkPropertyConsistency: consecutive non-formula columns of one property must agree on insertable. If one column writes on insert and a sibling of the same property has insertable = false, the mapping is contradictory and Hibernate throws this AnnotationException while binding the property.

Source

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

	}

	public void addColumn(AnnotatedColumn child) {
		columns.add( child );
	}

	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. Set the same insertable value on every column of the property
  2. If one part must stay read-only, map it as its own property (e.g. a separate read-only field) rather than mixing flags inside one mapping
  3. After fixing, verify updatable flags and table names too - the same consistency check validates them next

Example fix

// before: mixed insertable within one property
@Type(MoneyType.class)
@Columns({
    @Column(name = "amount"),                          // insertable = true
    @Column(name = "currency", insertable = false)     // mixes -> error
})
private Money price;

// after: consistent flags (or split into separate properties)
@Type(MoneyType.class)
@Columns({
    @Column(name = "amount"),
    @Column(name = "currency")
})
private Money price;
Defensive patterns

Strategy: validation

Validate before calling

// Before boot: all columns of one multi-column property must agree on insertable
static boolean insertableFlagsConsistent(Class<?> entity) {
    for (Field f : entity.getDeclaredFields()) {
        Columns cols = f.getAnnotation(Columns.class);
        if (cols == null || cols.value().length < 2) continue;
        boolean first = cols.value()[0].insertable();
        for (Column c : cols.value()) {
            if (c.insertable() != first) return false;
        }
    }
    return true;
}

Try / catch

try {
    final SessionFactory sf = new MetadataSources(standardServiceRegistry)
            .addAnnotatedClass(MyEntity.class)
            .buildMetadata()
            .buildSessionFactory();
} catch (AnnotationException | MappingException e) {
    throw new IllegalStateException("Invalid ORM mapping, aborting startup: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: A multi-column property where @Column/@AttributeOverride entries mix insertable = true (default) and insertable = false - commonly the read-only half of a composite mapping left non-insertable while the other half stays writable.

Common situations: Making one column of a composite read-only for trigger/generated-value reasons while forgetting the sibling columns; copy-pasted override blocks with stale insertable flags; splitting a property's columns across insert/update strategies.

Related errors


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