{"record":{"id":"73f12bcd57952bb7","repo":"hibernate/hibernate-orm","slug":"a-different-object-with-the-same-identifier-value-73f12b","errorCode":null,"errorMessage":"A different object with the same identifier value was already associated with this persistence context","messagePattern":"A different object with the same identifier value was already associated with this persistence context","errorType":"exception","errorClass":"NonUniqueObjectException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java","lineNumber":248,"sourceCode":"\t\t}\n\t\telse {\n\t\t\tassert id != null;\n\t\t\tkey = entityKey( id, persister, source );\n\t\t}\n\t\treturn performSaveOrReplicate( entity, key, persister, useIdentityColumn, context, source, delayIdentityInserts );\n\t}\n\n\t@Nonnull\n\tprivate static EntityKey entityKey(@Nonnull Object id, @Nonnull EntityPersister persister, @Nonnull EventSource source) {\n\t\tfinal var key = source.generateEntityKey( id, persister );\n\t\tfinal var persistenceContext = source.getPersistenceContextInternal();\n\t\tfinal Object old = persistenceContext.getEntity( key );\n\t\tif ( old != null ) {\n\t\t\tif ( persistenceContext.getEntry( old ).getStatus() == Status.DELETED ) {\n\t\t\t\tsource.forceFlush( persistenceContext.getEntry( old ) );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new NonUniqueObjectException( id, persister.getEntityName() );\n\t\t\t}\n\t\t}\n\t\telse if ( persistenceContext.containsDeletedUnloadedEntityKey( key ) ) {\n\t\t\tsource.forceFlush( key );\n\t\t}\n\t\treturn key;\n\t}\n\n\t/**\n\t * Performs all the actual work needed to persist an entity\n\t * (well to get the persist action moved to the execution queue).\n\t *\n\t * @param entity The entity to be persisted\n\t * @param key The id to be used for saving the entity (or null, in the case of identity columns)\n\t * @param persister The persister for the entity\n\t * @param useIdentityColumn Should an identity column be used for id generation?\n\t * @param context Generally cascade-specific information\n\t * @param source The session which is the source of the current event","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java#L230-L266","documentation":"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().","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: session already manages Customer#7\nCustomer detached = copyFromDto(dto); // different instance, same id\nsession.update(detached); // NonUniqueObjectException\n\n// after\nsession.merge(detached); // state copied onto the managed instance","handlingStrategy":"try-catch","validationCode":"// detect a managed instance with the same id before reattaching\nObject managed = session.find(Customer.class, detached.getId());\nif (managed != null && managed != detached) {\n    // decide: merge, or evict the managed instance\n    session.merge(detached);\n    return;\n}\nsession.update(detached);","typeGuard":null,"tryCatchPattern":"try {\n    session.update(detached);\n} catch (NonUniqueObjectException e) {\n    // another instance with the same id is already managed in this session\n    session.merge(detached); // copies state onto the managed instance\n}","preventionTips":["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"],"tags":["session","persistence-context","detached-entities","merge"],"backgroundTag":"non-unique-object-in-session","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}