hibernate/hibernate-orm · critical · ConcurrentModificationException
Found a different instance corresponding to instanceId [${in
Error message
Found a different instance corresponding to instanceId [${instanceId}], this might indicate a concurrent access to this persistence context. What it means
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.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/internal/util/collections/InstanceIdentityMap.java:123
* @param instanceId the instance id whose associated value is to be returned
* @param key key instance to double-check instance equality
* @return the value to which the specified instance id is mapped,
* or {@code null} if this map contains no mapping for the instance id
* @implNote This method accesses the backing array with the provided instance id, but performs an instance
* equality check ({@code ==}) with the provided key to ensure it corresponds to the mapped one
*/
public @Nullable V get(int instanceId, Object key) {
if ( instanceId <= 0 ) {
return null;
}
final Entry<K, V> entry = get( instanceId - 1 );
if ( entry != null ) {
if ( entry.getKey() == key ) {
return entry.getValue();
}
else {
throw new ConcurrentModificationException(
"Found a different instance corresponding to instanceId [" + instanceId +
"], this might indicate a concurrent access to this persistence context."
);
}
}
return null;
}
/**
* {@inheritDoc}
* @implNote This only works for {@link InstanceIdentity} keys, and it's inefficient
* since we need to do a type check. Prefer using {@link #get(int, Object)}.
*/
@Override
public @Nullable V get(Object key) {
if ( key instanceof InstanceIdentity instance ) {
return get( instance.$$_hibernate_getInstanceId(), instance );
}View on GitHub (pinned to fad1729dce)
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
Example fix
// before: Session shared across threads
List<Order> orders = ids.parallelStream()
.map( id -> session.get( Order.class, id ) ) // unsafe
.toList();
// after: each worker uses its own session
List<Order> orders = ids.parallelStream()
.map( id -> withSession( s -> s.get( Order.class, id ) ) )
.toList(); Defensive patterns
Strategy: try-catch
Try / catch
try {
return map.get( instanceId, entity );
} catch ( ConcurrentModificationException e ) {
// Persistence context corrupted by concurrent access: fail fast,
// close the session, and surface the thread-safety bug.
session.close();
throw new IllegalStateException("Session used concurrently; closing", e);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Found a different instance corresponding to instanceId [${in
- Illegal attempt to associate a collection with two open sess
- No row with the given identifier exists for entity " + infoS
- Newer version [" + latestVersion + "] of entity [" + infoStr
- %s for entity %s#%s
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/2118e5bdd9561c1d.
Report an issue: GitHub.