hibernate/hibernate-orm · error · AnnotationException

Column mappings for property

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.

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.

Appendix: 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)