{"record":{"id":"2118e5bdd9561c1d","repo":"hibernate/hibernate-orm","slug":"found-a-different-instance-corresponding-to-instan","errorCode":null,"errorMessage":"Found a different instance corresponding to instanceId [${instanceId}], this might indicate a concurrent access to this persistence context.","messagePattern":"Found a different instance corresponding to instanceId \\[(.+?)\\], this might indicate a concurrent access to this persistence context\\.","errorType":"exception","errorClass":"ConcurrentModificationException","httpStatus":null,"severity":"critical","filePath":"hibernate-core/src/main/java/org/hibernate/internal/util/collections/InstanceIdentityMap.java","lineNumber":123,"sourceCode":"\t * @param instanceId the instance id whose associated value is to be returned\n\t * @param key key instance to double-check instance equality\n\t * @return the value to which the specified instance id is mapped,\n\t * or {@code null} if this map contains no mapping for the instance id\n\t * @implNote This method accesses the backing array with the provided instance id, but performs an instance\n\t * equality check ({@code ==}) with the provided key to ensure it corresponds to the mapped one\n\t */\n\tpublic @Nullable V get(int instanceId, Object key) {\n\t\tif ( instanceId <= 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal Entry<K, V> entry = get( instanceId - 1 );\n\t\tif ( entry != null ) {\n\t\t\tif ( entry.getKey() == key ) {\n\t\t\t\treturn entry.getValue();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new ConcurrentModificationException(\n\t\t\t\t\t\t\"Found a different instance corresponding to instanceId [\" + instanceId +\n\t\t\t\t\t\t\"], this might indicate a concurrent access to this persistence context.\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * @implNote This only works for {@link InstanceIdentity} keys, and it's inefficient\n\t * since we need to do a type check. Prefer using {@link #get(int, Object)}.\n\t */\n\t@Override\n\tpublic @Nullable V get(Object key) {\n\t\tif ( key instanceof InstanceIdentity instance ) {\n\t\t\treturn get( instance.$$_hibernate_getInstanceId(), instance );\n\t\t}","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/util/collections/InstanceIdentityMap.java#L105-L141","documentation":"get(int instanceId, Object key) reads the entry slot for instanceId and then verifies slot identity (entry.getKey() == key). Instance ids are unique per enhanced instance inside a persistence context, so finding a different object under the same id means the map was mutated concurrently (or two instances illegally share an id) — Hibernate surfaces this as ConcurrentModificationException with an explicit hint about concurrent persistence-context access. It is a correctness alarm, not a recoverable lookup failure.","triggerScenarios":"Thread A calls get(id, entity) while thread B put() a different entity under the same instanceId in the same map — i.e. two threads using one Session/persistence context concurrently; also id collisions after manual misuse of the enhancement API.","commonSituations":"Sharing a Hibernate Session across threads (servlet threads, @Async methods, parallel streams over entity collections calling lazy loads); frameworks that pool or pass Sessions across executor boundaries without synchronization.","solutions":["Audit for Session sharing: one Session per thread, ever (session-per-request, session-per-async-job)","Move parallel entity work to separate Sessions opened inside each worker thread","Wrap external access to the persistence context in proper synchronization if sharing is truly unavoidable","After this exception, discard the Session — its state is suspect; do not continue with it"],"exampleFix":"// before: Session shared across threads\nList<Order> orders = ids.parallelStream()\n        .map( id -> session.get( Order.class, id ) )  // unsafe\n        .toList();\n// after: each worker uses its own session\nList<Order> orders = ids.parallelStream()\n        .map( id -> withSession( s -> s.get( Order.class, id ) ) )\n        .toList();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    return map.get( instanceId, entity );\n} catch ( ConcurrentModificationException e ) {\n    // Persistence context corrupted by concurrent access: fail fast,\n    // close the session, and surface the thread-safety bug.\n    session.close();\n    throw new IllegalStateException(\"Session used concurrently; closing\", e);\n}","preventionTips":["One Session per thread — never share a live Session across HTTP/async/parallel-stream boundaries","Pass detached data or ids between threads, not open Sessions","Log the thread name on every session acquisition in dev to catch sharing early","Treat this exception as a bug report, not a retryable error"],"tags":["hibernate","concurrency","thread-safety","persistence-context","session"],"backgroundTag":"session-concurrent-access","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}