No row with the given identifier exists: Hibernate 7 Fix

Hibernate throws “No row with the given identifier exists” when a proxy or an eager load asks for an id that has no row. See the real Hibernate 7.4 exceptions for getReference(), lazy and eager associations and concurrent deletes, and fix them with find(), orphan cleanup, a foreign key constraint or @NotFound.

Hibernate throws “No row with the given identifier exists” when it loads an entity by its id and the database has no row with that id. In most cases the entity is a proxy, a placeholder object that holds only the id and runs the SELECT on its first use, so the error shows up at a getter call, often far away from the code that created the proxy.

We meet the error when an id points to nothing, for example after a data import from an old system leaves an application row that refers to a deleted scholarship.

The following example shows the exception for Hibernate 7.4 with an EntityManagerFactory.

jakarta.persistence.EntityNotFoundException: No row with the given identifier exists for entity [com.howtodoinjava.hibernate.notfound.Scholarship with id '99']
Caused by: org.hibernate.ObjectNotFoundException: No row with the given identifier exists for entity [com.howtodoinjava.hibernate.notfound.Scholarship with id '99']

Notice that the message names the entity class and the id without a row. Older versions printed it as No row with the given identifier exists: [hibernate.test.dto.DepartmentEntity#11]. The fix depends on where the missing id came from, such as a wrong id passed to getReference(), a foreign key column that points to nothing, or a row that another transaction deleted.

Next, we reproduce each cause in a scholarship portal. After that, we fix the code, clean up the data and add the foreign key constraint that keeps broken rows out.

1. Why Hibernate Cannot Find the Row

The following example is a scholarship portal on Hibernate 7.4.11, Java 25 and an in-memory H2 database. A Scholarship has a name and an amount, and a ScholarshipApplication has the student’s name, the submission date and the scholarship as a lazy @ManyToOne. The table comes from an old system without a foreign key constraint, which we reproduce with ConstraintMode.NO_CONSTRAINT.

private String studentName;
private LocalDate submittedOn;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "scholarship_id",
    foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Scholarship scholarship;

A data import wrote the applications with native SQL. Lokesh’s row points to scholarship 99, which never existed, and the database accepts it.

insert into scholarship_application (studentName, submittedOn, scholarship_id)
values ('Lokesh', date '2026-09-15', 99)
Two tables: scholarship_application with Lokesh pointing to scholarship_id 99, which has no row, and Alex pointing to scholarship_id 1, Merit, 500.00; below, three outcomes when Lokesh's application is loaded: LAZY throws EntityNotFoundException on getName, EAGER throws FetchNotFoundException in find, @NotFound(IGNORE) returns null
Without a foreign key constraint, the database stores an id that has no row. The mapping decides when and how Hibernate reports it.

The example project maps the same table with one variant of ScholarshipApplication per case, namely EagerApplication, IgnoreApplication, ExceptionApplication and CheckedApplication.

1.1. getReference() With an Id That Does Not Exist

The method getReference() returns a proxy without running SQL, so it does not check that the row exists. The error comes at the first getter that needs data.

Scholarship ref = em.getReference(Scholarship.class, 99L);   // no SQL, Scholarship$HibernateProxy
Long id = ref.getId();                                       // 99, no SQL
String name = ref.getName();                                 // select s1_0.id,s1_0.amount,s1_0.name from Scholarship s1_0 where s1_0.id=?
                                                             // EntityNotFoundException ... with id '99'

The call Hibernate.initialize(ref) fails the same way, because it runs the same SELECT.

1.2. A Foreign Key That Points to a Missing Row

With LAZY fetching, Hibernate loads the application and puts a proxy with id 99 into its scholarship field. Loading works, and the error waits for the getter.

ScholarshipApplication app = em.find(ScholarshipApplication.class, 1L);
// select sa1_0.id,sa1_0.scholarship_id,sa1_0.studentName,sa1_0.submittedOn from scholarship_application sa1_0 where sa1_0.id=?
String student = app.getStudentName();               // "Lokesh"
Long scholarshipId = app.getScholarship().getId();   // 99, no SQL
String name = app.getScholarship().getName();        // select ... from Scholarship s1_0 where s1_0.id=?
                                                     // EntityNotFoundException ... with id '99'

With FetchType.EAGER, the default for @ManyToOne, the error moves into the load itself. The exception class depends on how we load the application.

EagerApplication eager = em.find(EagerApplication.class, 1L);
// select ea1_0.id,ea1_0.scholarship_id,s1_0.id,s1_0.amount,s1_0.name,... from scholarship_application ea1_0
//   left join Scholarship s1_0 on s1_0.id=ea1_0.scholarship_id where ea1_0.id=?
// FetchNotFoundException

List<EagerApplication> all = em.createQuery("from ScholarshipApplication", EagerApplication.class).getResultList();
// select ea1_0.id,ea1_0.scholarship_id,ea1_0.studentName,ea1_0.submittedOn from scholarship_application ea1_0
// select s1_0.id,s1_0.amount,s1_0.name from Scholarship s1_0 where s1_0.id=?
// EntityNotFoundException ... with id '99'
org.hibernate.FetchNotFoundException: Entity `com.howtodoinjava.hibernate.notfound.Scholarship` with identifier value `99` does not exist

1.3. The Row Was Deleted After the Proxy Was Created

Because a proxy only knows the id, another transaction can delete the row between creating the proxy and reading it, and without a foreign key nothing stops that delete.

emf.runInTransaction(em -> {
  Scholarship merit = em.find(ScholarshipApplication.class, 2L).getScholarship();   // proxy, id 1

  emf.runInTransaction(other -> other
      .createQuery("delete from Scholarship where id = :id")
      .setParameter("id", meritId)
      .executeUpdate());           // delete from Scholarship s1_0 where s1_0.id=?

  String name = merit.getName();   // select ... from Scholarship s1_0 where s1_0.id=?
                                   // EntityNotFoundException ... with id '1'
});
Sequence diagram with four lanes: transaction 1 loads Alex's application and receives a proxy for scholarship 1 with only the id; transaction 2 deletes scholarship 1 and commits; transaction 1 calls merit.getName(), the proxy runs select where id equals 1, gets 0 rows and throws EntityNotFoundException with id 1
The proxy was created while the row existed. It is loaded only at getName(), after the row is gone.

The causes come down to six cases, and each one fails at a different place.

CaseWhere it failsException
getReference() with a missing idFirst getter other than getId()EntityNotFoundException
LAZY @ManyToOne to a missing rowFirst getter on the proxyEntityNotFoundException
EAGER @ManyToOne, find()Inside find()FetchNotFoundException
EAGER @ManyToOne, queryInside getResultList()EntityNotFoundException
Row deleted after the proxy was createdFirst getter on the proxyEntityNotFoundException
Row deleted, then em.refresh()Inside refresh()EntityNotFoundException (see FAQ 3.3)

2. How to Fix It

Each fix depends on where the missing id comes from.

Decision tree: an id from a request or user input is fixed with find() and a null check; a foreign key column with orphaned rows is fixed by deleting or nulling the orphans and adding a real foreign key; legacy data we cannot change can use @NotFound(IGNORE), which forces eager loading and erases the id on save; a row deleted by another transaction is prevented by a foreign key or handled by catching EntityNotFoundException
Fixing the data and adding the constraint removes the cause. @NotFound(IGNORE) only hides it.

2.1. Use find() and Check for null

The method find() runs the SELECT at the call and returns null when the row does not exist, without an exception. We use it for any id that comes from a request or a user, such as a scholarship id in the URL of an application form.

// Before: returns a proxy, fails later at the first getter
Scholarship scholarship = em.getReference(Scholarship.class, id);

// After: null when the row is missing
Scholarship scholarship = em.find(Scholarship.class, id);   // select ... from Scholarship s1_0 where s1_0.id=?
if (scholarship == null) {
  // reject the request
}

The same check works for a lazy association. The proxy’s getId() needs no SQL, and find() with that id returns null even though the persistence context already holds the proxy.

ScholarshipApplication app = em.find(ScholarshipApplication.class, 1L);
Scholarship scholarship = em.find(Scholarship.class, app.getScholarship().getId());
// select ... from Scholarship s1_0 where s1_0.id=?
// scholarship = null, no exception

We keep getReference() for ids we trust, for example to set a foreign key on a new row.

2.2. Clean Up the Orphaned Rows

An orphaned row is a row whose foreign key value has no matching row in the referenced table. The HQL function fk() reads the foreign key column itself, without a join, so we can find the orphaned rows without loading the missing entity.

String orphans = """
    where fk(a.scholarship) is not null
      and not exists (select s from Scholarship s where s.id = fk(a.scholarship))""";

List<String> names = em.createQuery("select a.studentName from ScholarshipApplication a " + orphans, String.class)
    .getResultList();    // [Lokesh]
// select sa1_0.studentName from scholarship_application sa1_0 where sa1_0.scholarship_id is not null
//   and not exists(select s1_0.id from Scholarship s1_0 where s1_0.id=sa1_0.scholarship_id)

After that, we decide what the broken rows mean for the business, and we either delete them or keep them without a scholarship.

int deleted = em.createQuery("delete from ScholarshipApplication a " + orphans).executeUpdate();   // 1
int updated = em.createQuery("update ScholarshipApplication a set a.scholarship = null " + orphans)
    .executeUpdate();                                                                              // 1
// update scholarship_application sa1_0 set scholarship_id=null where sa1_0.scholarship_id is not null and not exists(...)

2.3. Add a Real Foreign Key Constraint

A foreign key constraint is the only fix that stops new broken rows, because the database itself rejects them. Adding the constraint fails while orphaned rows are still in the table, so we clean up first.

alter table scholarship_application
  add constraint fk_application_scholarship
  foreign key (scholarship_id) references Scholarship (id)
org.hibernate.exception.ConstraintViolationException: JDBC exception executing SQL [Referential integrity constraint violation: "FK_APPLICATION_SCHOLARSHIP: PUBLIC.SCHOLARSHIP_APPLICATION FOREIGN KEY(SCHOLARSHIP_ID) REFERENCES PUBLIC.SCHOLARSHIP(ID)"; ...]

When we remove ConstraintMode.NO_CONSTRAINT from the mapping, Hibernate’s schema tool creates the constraint too.

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "scholarship_id")
private Scholarship scholarship;
// alter table if exists scholarship_application add constraint FKpkw9fvccvf0vpycsyjlo7mic4 foreign key (scholarship_id) references Scholarship

With the constraint in place, the import and the delete from section 1 both fail with a clear error, instead of breaking a getter later.

ActionWithout the constraintWith the constraint
Insert scholarship_id = 99AcceptedConstraintViolationException
em.remove() of a scholarship that has applicationsAcceptedRollbackException at commit, caused by ConstraintViolationException
getReference(Scholarship.class, 99L).getName()EntityNotFoundExceptionEntityNotFoundException (fix: section 2.1)

2.4. Use @NotFound(IGNORE) for Data We Cannot Change

Sometimes another system owns the data, and we can neither clean it nor add a constraint. For that case, Hibernate provides the @NotFound annotation. With NotFoundAction.IGNORE, a missing row becomes null instead of an exception.

@ManyToOne(fetch = FetchType.LAZY)
@NotFound(action = NotFoundAction.IGNORE)
@JoinColumn(name = "scholarship_id")
private Scholarship scholarship;
Scholarship scholarship = em.find(IgnoreApplication.class, 1L).getScholarship();    // null
// select ia1_0.id,ia1_0.scholarship_id,ia1_0.studentName,ia1_0.submittedOn from scholarship_application ia1_0 where ia1_0.id=?
// select s1_0.id,s1_0.amount,s1_0.name from Scholarship s1_0 where s1_0.id=?

The second SELECT shows the first side effect. Hibernate must check the row to know whether to return null, so it ignores LAZY and logs a warning at startup.

WARN org.hibernate.orm.boot - HHH160133: 'com.howtodoinjava.hibernate.notfound.IgnoreApplication.scholarship' uses both @NotFound and FetchType.LAZY;@ManyToOne and @OneToOne associations mapped with @NotFound are forced to EAGER fetching

The @NotFound mapping has more side effects.

  • A query for two applications runs three statements, namely one for the applications and one per scholarship.
  • Saving the application erases the broken id. After setStudentName(“Lokesh Gupta”), Hibernate runs an update of scholarship_application that writes all columns, and scholarship_id changes from 99 to NULL.
  • Hibernate creates no foreign key constraint for a @NotFound association, so deleting a scholarship that has applications still works.
  • The HQL condition a.scholarship is null becomes a left join, so it also matches Lokesh’s row with scholarship_id = 99.

The value NotFoundAction.EXCEPTION, the default action of the annotation, has the same eager loading, but throws FetchNotFoundException inside find(). We use @NotFound(IGNORE) only for read-only access to data we cannot fix, because saving the entity erases the broken id and loses data.

3. ObjectNotFoundException FAQs

3.1. Is ObjectNotFoundException or EntityNotFoundException Thrown?

It depends on how Hibernate was started. The ObjectNotFoundException is Hibernate’s own class and extends HibernateException, not EntityNotFoundException.

Setup or caseException we catchCause
EntityManagerFactory (HibernatePersistenceConfiguration)jakarta.persistence.EntityNotFoundExceptionorg.hibernate.ObjectNotFoundException
Native SessionFactory from Configurationorg.hibernate.ObjectNotFoundExceptionnone
EAGER or @NotFound(EXCEPTION) in find()org.hibernate.FetchNotFoundExceptionnone

The first two carry the same message. Because FetchNotFoundException extends EntityNotFoundException, with an EntityManagerFactory, catching EntityNotFoundException covers every missing-row case from section 1.

3.2. What Replaced Session.load() in Hibernate 7?

Older Hibernate code used session.load(), which returned a proxy, and session.get(), which returned null. Hibernate 7.4 changes both.

  • The method Session.load(Class, id) no longer exists. The method getReference() replaces it and returns the same kind of proxy.
  • The method Session.get(Class, id) is deprecated. The method find() replaces it and returns null for a missing row.

Only the method load(Object, Object), which fills an object we pass in, is still on Session. On a native SessionFactory, session.getReference(Scholarship.class, 99L).getName() throws the plain ObjectNotFoundException from the table in FAQ 3.1.

3.3. Why Does refresh() Throw EntityNotFoundException?

The call em.refresh() reads the row again to replace the entity’s state. When another transaction deleted the row in the meantime, there is nothing to read.

Scholarship merit = em.find(Scholarship.class, meritId);
// another transaction: delete from Scholarship
em.refresh(merit);      // EntityNotFoundException: No row with the given identifier exists ... with id '1'
                        // caused by org.hibernate.UnresolvableObjectException

4. Conclusion

“No row with the given identifier exists” means a proxy or an eager load asked for an id that has no row. We use find() and a null check for ids from outside, whereas broken references need a cleanup of the orphaned rows and a foreign key constraint. We keep @NotFound(IGNORE) for read-only legacy data, knowing that it loads the association eagerly and erases the broken id on save.

5. References

Happy Learning !!

Source Code on Github

Leave a Comment

  1. I had that same exception using get() method. Do you know what could make it?
    I have a generic repository class that calls: getSessionFactory().getCurrentSession().get(getType(), id)
    My domain class is something like follows:
    public class MyClass{

    private MySecondClass mySecondClass;
    ………….

    }

    When I get a MyClass object and try to use mySecondClass’s getter in it, I get that exception. That happens when mySecondClass object is supposed to be null but it is a proxyfied class named something javaassist.

Comments are closed.

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.