hibernate/hibernate-orm · error · NonUniqueObjectException
A different object with the same identifier value was alread
Error message
A different object with the same identifier value was already associated with this persistence context
What it means
While preparing a save, AbstractSaveEventListener.entityKey() computes the EntityKey for the generated/assigned id and finds a different object instance already managed under that key in the persistence context (and not scheduled for deletion). It throws NonUniqueObjectException: within one Session only one instance per identifier may exist, and you are attaching a second copy via save()/update()/persist().
Source
Thrown at hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java:248
}
else {
assert id != null;
key = entityKey( id, persister, source );
}
return performSaveOrReplicate( entity, key, persister, useIdentityColumn, context, source, delayIdentityInserts );
}
@Nonnull
private static EntityKey entityKey(@Nonnull Object id, @Nonnull EntityPersister persister, @Nonnull EventSource source) {
final var key = source.generateEntityKey( id, persister );
final var persistenceContext = source.getPersistenceContextInternal();
final Object old = persistenceContext.getEntity( key );
if ( old != null ) {
if ( persistenceContext.getEntry( old ).getStatus() == Status.DELETED ) {
source.forceFlush( persistenceContext.getEntry( old ) );
}
else {
throw new NonUniqueObjectException( id, persister.getEntityName() );
}
}
else if ( persistenceContext.containsDeletedUnloadedEntityKey( key ) ) {
source.forceFlush( key );
}
return key;
}
/**
* Performs all the actual work needed to persist an entity
* (well to get the persist action moved to the execution queue).
*
* @param entity The entity to be persisted
* @param key The id to be used for saving the entity (or null, in the case of identity columns)
* @param persister The persister for the entity
* @param useIdentityColumn Should an identity column be used for id generation?
* @param context Generally cascade-specific information
* @param source The session which is the source of the current eventView on GitHub (pinned to fad1729dce)
Solutions
- Use merge() instead of update()/save() for detached instances — merge copies state onto the managed copy
- session.evict(managedInstance) or session.clear() before reattaching if you truly need the new instance
- Keep one Session per unit of work so detached copies never get attached alongside managed ones
- Load the entity in the same session and modify the managed instance instead of reattaching
Example fix
// before: session already manages Customer#7 Customer detached = copyFromDto(dto); // different instance, same id session.update(detached); // NonUniqueObjectException // after session.merge(detached); // state copied onto the managed instance
Defensive patterns
Strategy: try-catch
Validate before calling
// detect a managed instance with the same id before reattaching
Object managed = session.find(Customer.class, detached.getId());
if (managed != null && managed != detached) {
// decide: merge, or evict the managed instance
session.merge(detached);
return;
}
session.update(detached); Try / catch
try {
session.update(detached);
} catch (NonUniqueObjectException e) {
// another instance with the same id is already managed in this session
session.merge(detached); // copies state onto the managed instance
} Prevention
- Use merge() for detached instances instead of update()/save()
- Keep one instance per identifier per Session
- Load-modify-delete within a single unit of work
- Never attach copies built from DTOs next to managed originals
When it happens
Trigger: session.update(detachedCopy) while a different instance with the same id is already managed in the session; save() with an explicitly set id that collides with an already-loaded entity; a fresh detached copy built from a DTO reattached next to the managed original in the same session.
Common situations: Load-modify in one session, then also update() a detached copy of the same row; passing entities across sessions and reattaching them; import/sync routines re-saving existing rows.
Related errors
- Illegal attempt to associate a ManagedEntity with two open p
- Given entity is not associated with the persistence context
- Found a different instance corresponding to instanceId [${in
- Insert conflict 'do update' clause with constraint name is n
- Cannot lazily initialize collection
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/73f12bcd57952bb7.
Report an issue: GitHub.