hibernate/hibernate-orm · error · UnresolvableObjectException

No row with the given identifier exists

Error message

No row with the given identifier exists

What it means

UnresolvableObjectException (message 'No row with the given identifier exists') raised in DefaultRefreshEventListener.refresh when the entity's EntityEntry reports isExistsInDatabase() == false. The session has already concluded the backing row is gone — typically because a delete is pending/persisted in this session or the row vanished between load and refresh. The exception carries the identifier and entity name of the unreachable row.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java:144

			@Nonnull RefreshContext refreshedAlready,
			@Nonnull Object object) {
		final var source = event.getSession();
		final var persistenceContext = source.getPersistenceContextInternal();
		final var entry = persistenceContext.getEntry( object );

		if ( entry == null ) {
			throw new DetachedObjectException( "Given entity is not associated with the persistence context" );
		}

		final var persister = entry.getPersister();
		final Object id = entry.getId();

		if ( EVENT_LISTENER_LOGGER.isTraceEnabled() ) {
			EVENT_LISTENER_LOGGER.refreshing(
					infoString( persister, id, event.getFactory() ) );
		}
		if ( !entry.isExistsInDatabase() ) {
			throw new UnresolvableObjectException( id, persister.getEntityName() );
		}

		// cascade the refresh prior to refreshing this entity
		Cascade.cascade(
				CascadingActions.REFRESH,
				CascadePoint.BEFORE_REFRESH,
				source,
				persister,
				object,
				refreshedAlready
		);

		persistenceContext.removeEntityHolder( entry.getEntityKey() );
		if ( persister.hasCollections() ) {
			new EvictVisitor( source, object ).process( object, persister );
		}
		persistenceContext.removeEntry( object );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Do not refresh entities scheduled for deletion — reload instead: session.find(Entity.class, id) and treat a null result as deleted
  2. For concurrent deletes, catch UnresolvableObjectException (or pre-check existence with a fresh find/count query) and discard the stale reference gracefully
  3. Review cascade rules (CascadeType.REFRESH combined with REMOVE) so a cascade-refresh cannot reach entities pending delete

Example fix

// before
manager.remove(order);
session.refresh(order); // UnresolvableObjectException: row already gone

// after
manager.remove(order);
// never refresh a removed entity; reload if still needed:
Order fresh = session.find(Order.class, order.getId()); // null => deleted
Defensive patterns

Strategy: try-catch

Validate before calling

if (session.find(Order.class, order.getId()) != null) {
    session.refresh(order);
} // null means the row is gone — skip refresh

Type guard

null

Try / catch

try {
    session.refresh(order);
} catch (UnresolvableObjectException e) {
    // row deleted concurrently or pending delete: drop the stale reference
    log.info("Order {} no longer exists", e.getIdentifier());
    session.detach(order);
}

Prevention

When it happens

Trigger: session.refresh() (including cascade REFRESH from a parent) on an entity that was removed via session.remove()/delete() in the same unit of work before flush; refreshing an entity whose row was deleted by a concurrent transaction or a direct JDBC/DBA operation after it was loaded.

Common situations: Concurrent deletion by another user, batch job, or cleanup thread while a stale managed entity is still being refreshed; deleting and refreshing the same object in one service method; cascade=REFRESH reaching children already scheduled for cascade delete; test fixtures deleted mid-test while entities remain managed.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/2d2c10abe131f8ca. Report an issue: GitHub.