hibernate/hibernate-orm · error · LazyInitializationException

Cannot lazily initialize collection

Error message

Cannot lazily initialize collection

What it means

A lazy persistent collection stores its role and key; on first access it asks its owning session to load the data. throwLazyInitializationException fires when initialization is impossible because the session is closed or the collection is detached, producing the classic 'Cannot lazily initialize collection of role X with key Y' error. The message names the exact association that was touched outside a live session.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/collection/spi/AbstractPersistentCollection.java:667

	private void throwLazyInitializationExceptionIfNotConnected() {
		if ( !isConnectedToSession() ) {
			throwLazyInitializationException( "no session or session was closed" );
		}
		if ( !session.isConnected() ) {
			throwLazyInitializationException( "session is disconnected" );
		}
	}

	private void throwLazyInitializationException(String message) {
		final var error = new StringBuilder( "Cannot lazily initialize collection" );
		if ( role != null ) {
			error.append( " of role '" ).append( role ).append( "'" );
		}
		if ( key != null ) {
			error.append( " with key '" ).append( key ).append( "'" );
		}
		error.append( " (" ).append( message ).append( ")" );
		throw new LazyInitializationException( error.toString() );
	}

	public static void checkPersister(PersistentCollection<?> collection, CollectionPersister persister) {
		if ( !collection.wasInitialized() && persister == null ) {
			throw new LazyInitializationException( "Cannot lazily initialize collection"
													+ " (collection is being removed)" );
		}
	}

	protected final void setInitialized() {
		this.initializing = false;
		this.initialized = true;
	}

	@Override
	public boolean isInitializing() {
		return initializing;
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Initialize the collection inside the session: Hibernate.initialize(parent.getChildren()) or a touch like size() within the transaction
  2. Fetch what you need in the query: JOIN FETCH, @EntityGraph, or @Fetch(JOIN) for that read path
  3. Project to DTOs inside the service layer instead of returning entities
  4. Widen the @Transactional boundary so the whole read happens in one open session

Example fix

// before
@Transactional(readOnly = true)
public Order getOrder(Long id) { return repo.findById(id).orElseThrow(); }
// caller after commit: order.getLines().size(); -> LazyInitializationException

// after
@Transactional(readOnly = true)
public Order getOrder(Long id) {
    return em.createQuery(
            "select o from Order o join fetch o.lines where o.id = :id", Order.class)
            .setParameter("id", id).getSingleResult();
}
Defensive patterns

Strategy: validation

Validate before calling

if (order.getLines() instanceof PersistentCollection pc
        && !pc.wasInitialized()
        && !session.isOpen()) {
    throw new IllegalStateException(
            "order.lines is lazy and the session is closed - initialize inside the transaction");
}

Type guard

static boolean isSafeToAccess(Collection<?> c, SharedSessionContract session) {
    return !(c instanceof PersistentCollection pc)
            || pc.wasInitialized()
            || (session != null && session.isOpen());
}

Try / catch

try {
    return order.getLines().size();
} catch (LazyInitializationException e) {
    // recover by reloading the owner in a fresh session
    try (Session s = sessionFactory.openSession()) {
        return s.find(Order.class, order.getId()).getLines().size();
    }
}

Prevention

When it happens

Trigger: Calling size(), iterator(), stream(), contains() or get() on a lazy @OneToMany collection after the owning session/EntityManager closed; serializing detached entities to JSON; touching the collection in another thread or after transaction end with OSIV disabled.

Common situations: Spring MVC controllers returning JPA entities with lazy relations after the service transaction ended; async jobs or executors receiving detached entities; unit tests reading collections outside transactional scope.

Related errors


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