How to resolve javax.persistence.NoResultException OR javax.persistence.NonUniqueResultException in JPA

Introduction

This tutorial explains the two exceptions JPA throws when a query that should return exactly one result does not: NoResultException, when it finds nothing, and NonUniqueResultException, when it finds more than one. We will see why getSingleResult() throws them, and then four ways to handle a query that may find nothing: catching the exceptions, Jakarta Persistence 3.2's getSingleResultOrNull(), getResultStream().findFirst(), and a Spring Data repository returning Optional. A program runs each of them for zero, one and two matching rows, and prints the real results and exception messages.

(Updated in November 2026. Since Jakarta EE 9, the exceptions are jakarta.persistence.NoResultException and jakarta.persistence.NonUniqueResultException; in older applications - Java EE, and Spring Boot 2 and earlier - they are in the javax.persistence package. Everything below applies to both.)

Why the exceptions are thrown

If you are getting one of these exceptions -
  • NoResultException: No result found for query [...] (older Hibernate versions say "No entity found for query")
  • NonUniqueResultException: Query did not return a unique result: 2 results were returned
then the code called getSingleResult() on a query, and the query returned no rows, or more than one. getSingleResult() is strict on purpose: it promises exactly one result, and treats anything else as an error. That is right when the row must exist - for example, loading a user whose id was just shown in a drop-down list filled from the same table - and wrong for "find the user with this email, if there is one". For the second case, use one of the alternatives below instead of catching exceptions.

The usual causes are a where clause on a column that is not unique (two users in the same city), a value that does not exist (a mistyped id, a deleted row), and a missing parameter or a wrong comparison that matches nothing.

The example

Three users, two of them in Delhi. The table is named app_user, since USER is a reserved word in H2, PostgreSQL and other databases. The program runs on Spring Boot with Hibernate 7 and an in-memory H2 database -
User.java
//User.java
package com.javabrahman.jpa.singleresult;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "app_user")   // USER is a reserved word in several databases
public class User {
  @Id
  private int userId;
  private String name;
  private String city;

  protected User() {
  }

  public User(int userId, String name, String city) {
    this.userId = userId;
    this.name = name;
    this.city = city;
  }

  public String getName() { return name; }
}
UserRepository.java - the Spring Data way
//UserRepository.java
package com.javabrahman.jpa.singleresult;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Integer> {
  Optional<User> findByName(String name);
  Optional<User> findByCity(String city);
}
The queries use TypedQuery<User>, created with the result class, so that no casts are needed, and standard JPQL: select u from User u where u.userId = :userId. The shorter from User where userId = :userId works in Hibernate, as an HQL extension, but is not portable JPQL -
SingleResultApp.java - zero, one and two results, with each API
//SingleResultApp.java
package com.javabrahman.jpa.singleresult;

import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.util.function.Supplier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.support.TransactionTemplate;

@SpringBootApplication
public class SingleResultApp {

  @Bean
  CommandLineRunner demo(EntityManager em, TransactionTemplate tx, UserRepository users) {
    return args -> {
      tx.executeWithoutResult(s -> {
        em.persist(new User(1, "Ann", "Pune"));
        em.persist(new User(2, "Raj", "Delhi"));
        em.persist(new User(3, "Eve", "Delhi"));
      });

      tx.executeWithoutResult(s -> {
        System.out.println("== getSingleResult()");
        show("one match  (userId 1)  ", () -> byId(em, 1).getSingleResult().getName());
        show("no match   (userId 99) ", () -> byId(em, 99).getSingleResult().getName());
        show("two matches (Delhi)    ", () -> byCity(em, "Delhi").getSingleResult().getName());

        System.out.println("== getSingleResultOrNull() - Jakarta Persistence 3.2");
        show("no match   (userId 99) ", () -> byId(em, 99).getSingleResultOrNull());
        show("two matches (Delhi)    ", () -> byCity(em, "Delhi").getSingleResultOrNull());

        System.out.println("== getResultStream().findFirst()");
        show("no match   (userId 99) ", () -> byId(em, 99).getResultStream().findFirst());
        show("two matches (Delhi)    ", () -> byCity(em, "Delhi").getResultStream().findFirst().map(User::getName));
      });

      System.out.println("== Spring Data repository returning Optional");
      show("findByName(\"Ann\")      ", () -> users.findByName("Ann").map(User::getName));
      show("findByName(\"Max\")      ", () -> users.findByName("Max"));
      show("findByCity(\"Delhi\")    ", () -> users.findByCity("Delhi"));
    };
  }

  private static TypedQuery<User> byId(EntityManager em, int id) {
    return em.createQuery("select u from User u where u.userId = :userId", User.class).setParameter("userId", id);
  }

  private static TypedQuery<User> byCity(EntityManager em, String city) {
    return em.createQuery("select u from User u where u.city = :city order by u.userId", User.class).setParameter("city", city);
  }

  private static void show(String what, Supplier<Object> query) {
    try {
      System.out.println(what + " -> " + query.get());
    } catch (RuntimeException e) {
      System.out.println(what + " -> " + e.getClass().getName() + ": " + e.getMessage());
    }
  }

  public static void main(String[] args) {
    SpringApplication.run(SingleResultApp.class, args);
  }
}
 OUTPUT of the above code
== getSingleResult()
one match  (userId 1)   -> Ann
no match   (userId 99)  -> jakarta.persistence.NoResultException: No result found for query [select u from User u where u.userId = :userId]
two matches (Delhi)     -> jakarta.persistence.NonUniqueResultException: Query did not return a unique result: 2 results were returned
== getSingleResultOrNull() - Jakarta Persistence 3.2
no match   (userId 99)  -> null
two matches (Delhi)     -> jakarta.persistence.NonUniqueResultException: Query did not return a unique result: 2 results were returned
== getResultStream().findFirst()
no match   (userId 99)  -> Optional.empty
two matches (Delhi)     -> Optional[Raj]
== Spring Data repository returning Optional
findByName("Ann")       -> Optional[Ann]
findByName("Max")       -> Optional.empty
findByCity("Delhi")     -> org.springframework.dao.IncorrectResultSizeDataAccessException: Query did not return a unique result: 2 results were returned

Explanation of the output

  • getSingleResult() returned Ann for user 1, threw NoResultException for user 99, and threw NonUniqueResultException for Delhi, "2 results were returned". If you use it, catch NoResultException only where "not found" is a normal outcome, and treat NonUniqueResultException as a bug in the query or the data.
  • getSingleResultOrNull(), new in Jakarta Persistence 3.2, returned null for user 99 instead of throwing. Two results are still an error: it threw NonUniqueResultException for Delhi, which is usually what you want.
  • getResultStream().findFirst() returned Optional.empty for user 99, and for Delhi Optional[Raj], the first of the two. It never complains about extra rows, so use it only when "any one of them" is really acceptable - with an order by, as here, so that "first" is well defined.
  • A Spring Data repository method declared as Optional<User> returned Optional[Ann] and Optional.empty, with no exception for a missing row. For two rows, it threw Spring's IncorrectResultSizeDataAccessException, which wraps the JPA NonUniqueResultException. A repository method returning a plain User returns null when nothing is found.

Which one to use

  • The row must exist, and its absence is an error: getSingleResult(), or EntityManager.find() for lookups by primary key, which returns null instead of throwing.
  • The row may not exist: getSingleResultOrNull() with JPA 3.2 and later, or a repository method returning Optional. In older JPA versions, getResultList() and checking whether the list is empty does the same.
  • Several rows are possible and you want one of them: add an order by and use getResultStream().findFirst(), setMaxResults(1), or a derived query such as findFirstByCityOrderByUserId.
  • Prevent NonUniqueResultException at the source with a unique constraint on the column you look up by, such as an email address.

Summary

In this tutorial we saw that NoResultException and NonUniqueResultException come from getSingleResult(), which accepts exactly one result. A real run showed both exceptions with their current Hibernate messages, then getSingleResultOrNull() returning null for no result while still refusing two, getResultStream().findFirst() returning an Optional, and a Spring Data repository returning Optional and reporting two results as IncorrectResultSizeDataAccessException. For more on repository methods, see Spring Data JPA derived query methodsClick to read tutorial: Spring Data JPA Derived Query Methods Explained and @Query with JPQL and native queriesClick to read tutorial: Spring Data JPA @Query: JPQL and Native Queries.