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)

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'
});

The causes come down to six cases, and each one fails at a different place.
| Case | Where it fails | Exception |
|---|---|---|
| getReference() with a missing id | First getter other than getId() | EntityNotFoundException |
| LAZY @ManyToOne to a missing row | First getter on the proxy | EntityNotFoundException |
| EAGER @ManyToOne, find() | Inside find() | FetchNotFoundException |
| EAGER @ManyToOne, query | Inside getResultList() | EntityNotFoundException |
| Row deleted after the proxy was created | First getter on the proxy | EntityNotFoundException |
| 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.

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.
| Action | Without the constraint | With the constraint |
|---|---|---|
| Insert scholarship_id = 99 | Accepted | ConstraintViolationException |
| em.remove() of a scholarship that has applications | Accepted | RollbackException at commit, caused by ConstraintViolationException |
| getReference(Scholarship.class, 99L).getName() | EntityNotFoundException | EntityNotFoundException (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 case | Exception we catch | Cause |
|---|---|---|
| EntityManagerFactory (HibernatePersistenceConfiguration) | jakarta.persistence.EntityNotFoundException | org.hibernate.ObjectNotFoundException |
| Native SessionFactory from Configuration | org.hibernate.ObjectNotFoundException | none |
| EAGER or @NotFound(EXCEPTION) in find() | org.hibernate.FetchNotFoundException | none |
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
- Hibernate ORM 7.4 User Guide: @NotFound
- Hibernate ORM 7.4 User Guide: Obtain an entity reference without initializing its data
- ObjectNotFoundException JavaDoc (Hibernate 7.4)
- FetchNotFoundException JavaDoc (Hibernate 7.4)
- NotFound JavaDoc (Hibernate 7.4)
- EntityNotFoundException JavaDoc (Jakarta Persistence 3.2)
- EntityManager JavaDoc (Jakarta Persistence 3.2)
Happy Learning !!
You may want to try removing Orphan records, please refer my post below.
https://stackoverflow.com/questions/8984837/org-hibernate-objectnotfoundexception-no-row-with-the-given-identifier-exists/40513787#40513787
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.
Great. I agree with your argument.Is you brother of Arun Gupta?
Nope