hibernate/hibernate-orm · error · IllegalStateException

Mismatch between generated column values and identifier colu

Error message

Mismatch between generated column values and identifier columns for %s

What it means

For identifiers generated on execution (OnExecutionGenerator - identity-like generation, database functions or triggers assigning the PK), InsertCoordinatorStandard applies the generator's column inclusions and referenced column values to the key columns. IllegalStateException 'Mismatch between generated column values and identifier columns' means getReferencedColumnValues(dialect, INSERT) returned an array whose length differs from the identifier column count of the table.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/InsertCoordinatorStandard.java:576

		entityPersister().addDiscriminatorToInsertGroup( insertGroupBuilder );
		entityPersister().addAuxiliaryToInsertGroup( insertGroupBuilder );

		// add the keys
		insertGroupBuilder.forEachTableMutationBuilder( (tableMutationBuilder) -> {
			final var tableInsertBuilder = (TableInsertBuilder) tableMutationBuilder;
			final var tableMapping = (EntityTableMapping) tableInsertBuilder.getMutatingTable().getTableMapping();
			final var keyMapping = tableMapping.getKeyMapping();
			if ( tableMapping.isIdentifierTable()
					&& entityPersister().isIdentifierAssignedByInsert()
					&& !forceIdentifierBinding ) {
				assert entityPersister().getInsertDelegate() != null;
				final var generator = (OnExecutionGenerator) entityPersister().getGenerator();
				final boolean[] columnInclusions = generator.getColumnInclusions( dialect, EventType.INSERT );
				final String[] columnValues = generator.getReferencedColumnValues( dialect, EventType.INSERT );
				final int keyColumnCount = keyMapping.getColumnCount();
				if ( columnInclusions != null ) {
					if ( columnValues != null && columnValues.length != keyColumnCount ) {
						throw new IllegalStateException(
								"Mismatch between generated column values and identifier columns for "
										+ entityPersister().getEntityName()
						);
					}
					for ( int i = 0; i < keyColumnCount; i++ ) {
						if ( columnInclusions[i] ) {
							final String valueExpression =
									columnValues == null
											? keyMapping.getKeyColumn( i ).getWriteExpression()
											: columnValues[i];
							tableInsertBuilder.addColumnAssignment( keyMapping.getKeyColumn( i ), valueExpression );
						}
					}
				}
				else if ( generator.referenceColumnsInSql( dialect, EventType.INSERT ) ) {
					if ( columnValues != null ) {
						assert columnValues.length == 1;
						assert keyColumnCount == 1;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Return null from getReferencedColumnValues when the database assigns values via the key columns' write expressions
  2. Otherwise return exactly keyColumnCount values, in the same order as the key columns
  3. Keep getColumnInclusions length aligned with the identifier columns as well
  4. Add a CI insert test per generator-backed entity so contract mismatches fail at build time

Example fix

// before: values array does not match identifier column count
public class TriggerPkGenerator implements OnExecutionGenerator {
    @Override
    public String[] getReferencedColumnValues(Dialect d, EventType t) {
        return new String[] { "gen_pk()" }; // breaks for composite keys (2 columns)
    }
}

// after: let each key column use its own write expression
@Override
public String[] getReferencedColumnValues(Dialect d, EventType t) {
    return null; // null -> per-column write expressions, count always matches
}
Defensive patterns

Strategy: validation

Validate before calling

// unit test: generator contract must match identifier column count
@Test void generatorValuesMatchKeyColumns() {
    String[] vals = generator.getReferencedColumnValues(dialect, EventType.INSERT);
    int keyCols = metadata.getEntityBinding(Entity.class.getName())
            .getRootTable().getPrimaryKey().getColumns().size();
    assertTrue(vals == null || vals.length == keyCols,
        "getReferencedColumnValues length must equal identifier column count or be null");
}

Try / catch

try { session.persist(entity); tx.commit(); } catch (IllegalStateException e) { if (e.getMessage().contains("generated column values")) { /* fix generator to return null or keyColumnCount values */ } throw e; }

Prevention

When it happens

Trigger: A custom OnExecutionGenerator whose getReferencedColumnValues returns a hardcoded array shorter or longer than the key (typically written for single-column ids and reused on @EmbeddedId/@IdClass entities); returning an empty array instead of null; composite keys where only some columns get values.

Common situations: Implementing PK-by-trigger or PK-by-database-function generators; migrating an identity-style generator to a composite-key entity; Hibernate upgrades where the null-vs-array contract (null = use the key columns' write expressions) tightened.

Related errors


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