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
- Verify the table DDL actually auto-generates the id (AUTO_INCREMENT / IDENTITY / SERIAL / GENERATED AS IDENTITY) and migrate the schema if it drifted
- Prefer GenerationType.SEQUENCE with an allocated sequence (or UUID) over IDENTITY - it does not depend on getGeneratedKeys behavior
- On Oracle with trigger-based ids, move to identity columns or sequences with the proper dialect, and remove the trigger workaround
- 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
- Let Hibernate/Liquibase own the schema so column definitions always match the GenerationType
- Prefer SEQUENCE (with allocation) or UUID over IDENTITY for portability and batch-friendliness
- Run insert+flush smoke tests per database/driver pair in CI (including testcontainers images)
- Watch for insert triggers that swallow generated-key returns on Oracle/SQL Server
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
- ${getClass().getName()} does not support identity key genera
- dialect does not support sequences
- Summarization is not supported by DBMS
- Summarization is not supported by DBMS
- Summarization is not supported by DBMS!
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/5a8ccd79c8baa1ad.
Report an issue: GitHub.