hibernate/hibernate-orm · error · NullPointerException

null passed to Session.evict()

Error message

null passed to Session.evict()

What it means

DefaultEvictEventListener.onEvict() rejects a null argument with NullPointerException('null passed to Session.evict()'). evict() detaches one specific managed entity; passing null is a caller programming error, and Hibernate fails fast with an explicit message instead of silently ignoring the call.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java:45

 *
 * @author Steve Ebersole
 */
public class DefaultEvictEventListener implements EvictEventListener {

	/**
	 * Handle the given evict event.
	 *
	 * @param event The evict event to be handled.
	 *
	 */
	@Override
	public void onEvict(@Nonnull EvictEvent event) {
		final var source = event.getSession();
		final var persistenceContext = source.getPersistenceContextInternal();
		final Object object = event.getObject();
		//noinspection ConstantValue
		if ( object == null ) {
			throw new NullPointerException( "null passed to Session.evict()" );
		}
		final var lazyInitializer = extractLazyInitializer( object );
		if ( lazyInitializer != null ) {
			final Object id = lazyInitializer.getInternalIdentifier();
			if ( id == null ) {
				throw new IllegalArgumentException( "Could not determine identifier of proxy passed to evict()" );
			}
			final var persister =
					source.getFactory().getMappingMetamodel()
							.getEntityDescriptor( lazyInitializer.getEntityName() );
			final var key = source.generateEntityKey( id, persister );
			final var holder = persistenceContext.detachEntity( key );
			// if the entity has been evicted then its holder is null
			if ( holder != null && !lazyInitializer.isUninitialized() ) {
				final Object entity = holder.getEntity();
				if ( entity != null ) {
					final var entry = persistenceContext.removeEntry( entity );
					doEvict( entity, key, entry.getPersister(), event.getSession() );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Null-check the reference before evict/detach
  2. Use Objects.requireNonNull(entity, ...) to fail with your own message at the correct call site
  3. Reconsider whether evict() should run at all for optional references — it only applies to managed entities
  4. Guard loops that evict collections with filter(Objects::nonNull)

Example fix

// before
session.evict(maybeCustomer); // maybeCustomer may be null

// after
if (maybeCustomer != null) {
    session.evict(maybeCustomer);
}
Defensive patterns

Strategy: validation

Validate before calling

java.util.Objects.requireNonNull(entity, "entity to evict must not be null");
session.evict(entity);

Type guard

static boolean evictable(Object o) {
    return o != null;
}

Prevention

When it happens

Trigger: Session.evict(null) or EntityManager.detach(null) — typically a null flowing from an optional lookup, Map.get() miss, or unwrapped Optional into the detach call.

Common situations: Cleanup code evicting entities from a map of optional results; helper methods that evict 'previous' entities when no previous exists; null returned by find() feeding an unconditional evict.

Related errors


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