Introduction

LazyInitializationException occurs when Hibernate tries to lazily load an entity association after the database session has been closed. This is one of the most common JPA/Hibernate errors, especially when lazy-loaded collections are accessed in the view layer or after the service method returns.

The error message "could not initialize proxy - no Session" indicates that the entity proxy cannot load its data because the EntityManager is no longer available.

Symptoms

  • Application throws "org.hibernate.LazyInitializationException: could not initialize proxy - no Session"
  • Error occurs when accessing a lazy-loaded collection in the controller or view layer
  • Same code works in unit tests but fails in the full application

Common Causes

  • Lazy-loaded collection accessed after the service transaction commits
  • Entity returned from service layer and then its associations are accessed in the controller
  • OSIV (Open Session in View) pattern disabled but code depends on it

Step-by-Step Fix

  1. 1.Use JOIN FETCH in the query to eagerly load associations: Load needed data in the original query.
  2. 2.```java
  3. 3.public interface UserRepository extends JpaRepository<User, Long> {
  4. 4.@Query("SELECT DISTINCT u FROM User u " +
  5. 5."LEFT JOIN FETCH u.orders " +
  6. 6."LEFT JOIN FETCH u.address " +
  7. 7."WHERE u.id = :id")
  8. 8.Optional<User> findByIdWithOrders(@Param("Long") id);
  9. 9.}
  10. 10.`
  11. 11.Use EntityGraph for dynamic fetch planning: Define fetch plans without modifying queries.
  12. 12.```java
  13. 13.@Entity
  14. 14.@NamedEntityGraph(name = "User.withOrders",
  15. 15.attributeNodes = @NamedAttributeNode("orders"))
  16. 16.public class User {
  17. 17.@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
  18. 18.private List<Order> orders;
  19. 19.}

// Usage: EntityGraph<User> graph = entityManager.createEntityGraph(User.class); graph.addSubgraph("orders"); Map<String, Object> hints = Map.of("javax.persistence.fetchgraph", graph); User user = entityManager.find(User.class, id, hints); ```

  1. 1.Initialize collections within the transaction: Access lazy properties before the session closes.
  2. 2.```java
  3. 3.@Transactional(readOnly = true)
  4. 4.public UserDto getUserWithOrders(Long userId) {
  5. 5.User user = userRepository.findById(userId)
  6. 6..orElseThrow(() -> new NotFoundException("User not found"));

// Force initialization within transaction Hibernate.initialize(user.getOrders());

return UserDto.from(user); // Convert to DTO before leaving transaction } ```

Prevention

  • Always convert entities to DTOs within the service layer (before session closes)
  • Use JOIN FETCH or EntityGraph to explicitly load associations you need
  • Avoid the Open Session in View pattern -- it hides lazy loading issues until production
  • Use static analysis tools to detect lazy property access outside transactions