hibernate/hibernate-orm · critical · IdentifierGenerationException

Null id generated for entity '%s'

Error message

Null id generated for entity '%s'

What it means

PostInsertHandling (PostInsertHandling.java:153) applies the identifier generated by the database after an insert: if the retrieved generated id is null it throws IdentifierGenerationException("Null id generated for entity '<entity>'"). The INSERT executed but the JDBC driver/dialect returned no generated key, or the generator produced null - so Hibernate cannot complete the insert bookkeeping and the flush aborts. Common culprits are GenerationType.IDENTITY on a column that is not actually auto-increment, or a driver/trigger combination that breaks getGeneratedKeys/RETURNING.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/internal/decompose/entity/PostInsertHandling.java:153

		}

		Object generatedId = generatedValues.getGeneratedValue( persister.getIdentifierMapping() );
		if ( generatedId == null ) {
			generatedId = persister.getIdentifier( entity, session );
		}
		if ( generatedId != null ) {
			identifierHandle.set( generatedId );
			persister.setIdentifier( entity, generatedId, session );
			if ( action instanceof EntityIdentityInsertAction identityInsertAction ) {
				identityInsertAction.setGeneratedId( generatedId );
				final var entityKey = session.generateEntityKey( generatedId, persister );
				identityInsertAction.setEntityKey( entityKey );
				session.getPersistenceContextInternal().checkUniqueness( entityKey, entity );
			}
			return generatedId;
		}
		else {
			throw new IdentifierGenerationException(
					"Null id generated for entity '" + persister.getEntityName() + "'"
			);
		}
	}

	private void handleGeneratedProperties(
			Object id,
			EntityEntry entry,
			GeneratedValues generatedValues,
			PersistenceContext persistenceContext,
			EntityPersister persister,
			Object[] state) {

		if ( persister.hasInsertGeneratedProperties() ) {
			final Object instance = action.getInstance();
			persister.processInsertGeneratedProperties(
					id,
					instance,

View on GitHub (pinned to fad1729dce)

Solutions

  1. Verify the table DDL actually auto-generates the id (AUTO_INCREMENT / IDENTITY / SERIAL / GENERATED AS IDENTITY) and migrate the schema if it drifted
  2. Prefer GenerationType.SEQUENCE with an allocated sequence (or UUID) over IDENTITY - it does not depend on getGeneratedKeys behavior
  3. On Oracle with trigger-based ids, move to identity columns or sequences with the proper dialect, and remove the trigger workaround
  4. Check the JDBC driver matches the database version and the Hibernate dialect matches the database - then retest insert+flush in isolation

Example fix

// before - IDENTITY strategy but the column is a plain INT (no auto-increment)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;            // insert succeeds, generated key comes back null

// after - use a sequence that Hibernate controls
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "person_seq")
@SequenceGenerator(name = "person_seq", sequenceName = "person_seq", allocationSize = 50)
private Long id;
Defensive patterns

Strategy: validation

Validate before calling

// after persist/flush of a generated-id entity, verify the id materialized
em.persist(entity);
em.flush();
if (em.getIdentifier(entity) == null) {
    throw new IllegalStateException(
        "id generator returned null for " + entity.getClass().getName()
        + " - check GenerationType vs actual column definition");
}

Try / catch

try {
    em.getTransaction().begin();
    em.persist(e);
    em.getTransaction().commit();
} catch (IdentifierGenerationException ex) {
    // generated keys came back null: verify DDL (AUTO_INCREMENT/IDENTITY/SERIAL),
    // driver version, and dialect; consider switching to SEQUENCE/UUID
    throw new IllegalStateException("id generation broken for " + e.getClass(), ex);
}

Prevention

When it happens

Trigger: strategy = GenerationType.IDENTITY but the physical column lacks AUTO_INCREMENT/IDENTITY/SERIAL (DDL drift between environments); insert triggers (Oracle trigger-based id simulation, SQL Server INSTEAD OF triggers) that make getGeneratedKeys return null; custom or dialect-specific generators returning null; mismatched dialect for the actual database.

Common situations: Schema managed by hand or by a different tool (Liquibase/Flyway script forgot AUTO_INCREMENT); Oracle/SQL Server with trigger-based sequences; pointing a dialect for the wrong database version; upgrading the JDBC driver and generated-keys behavior changes; test containers using a different DB engine than production.

Related errors


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