{"record":{"id":"147e76fa00256d05","repo":"hibernate/hibernate-orm","slug":"sql-query-returned-no-results","errorCode":null,"errorMessage":"SQL query returned no results","messagePattern":"SQL query returned no results","errorType":"exception","errorClass":"NoRowException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/sql/results/spi/SingleResultConsumer.java","lineNumber":48,"sourceCode":"\t}\n\n\t@Override\n\tpublic T consume(\n\t\t\tJdbcValues jdbcValues,\n\t\t\tSharedSessionContractImplementor session,\n\t\t\tJdbcValuesSourceProcessingOptions processingOptions,\n\t\t\tJdbcValuesSourceProcessingState jdbcValuesSourceProcessingState,\n\t\t\tRowProcessingStateStandardImpl rowProcessingState,\n\t\t\tRowReader<T> rowReader) {\n\t\tfinal var persistenceContext = session.getPersistenceContextInternal();\n\t\tRuntimeException ex = null;\n\t\tpersistenceContext.beforeLoad();\n\t\tpersistenceContext.getLoadContexts().register( jdbcValuesSourceProcessingState );\n\t\ttry {\n\t\t\trowReader.startLoading( rowProcessingState );\n\t\t\tfinal boolean hadResult = rowProcessingState.next();\n\t\t\tif ( !hadResult ) {\n\t\t\t\tthrow new NoRowException( \"SQL query returned no results\" );\n\t\t\t}\n\t\t\tfinal T result = rowReader.readRow( rowProcessingState );\n\t\t\trowProcessingState.finishRowProcessing( true );\n\t\t\tjdbcValuesSourceProcessingState.registerSubselects();\n\t\t\trowReader.finishUp( rowProcessingState );\n\t\t\tjdbcValuesSourceProcessingState.finishUp();\n\t\t\treturn result;\n\t\t}\n\t\tcatch (RuntimeException e) {\n\t\t\tex = e;\n\t\t}\n\t\tfinally {\n\t\t\ttry {\n\t\t\t\tjdbcValues.finishUp( session );\n\t\t\t\tpersistenceContext.afterLoad();\n\t\t\t\tpersistenceContext.getLoadContexts().deregister( jdbcValuesSourceProcessingState );\n\t\t\t\tpersistenceContext.initializeNonLazyCollections();\n\t\t\t}","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/sql/results/spi/SingleResultConsumer.java#L30-L66","documentation":"Thrown by SingleResultConsumer when a query executed with single-result semantics returns zero rows (rowProcessingState.next() was false). In this codebase it surfaces from `SelectionQuery.getResultCount()` (SelectionQueryImpl:1035), the native-query count plan (NativeQueryImpl:1082), and the pessimistic-locking re-select (SqlAstBasedLockingStrategy:176) - for a versioned entity that path converts it into StaleObjectStateException, for an unversioned one it propagates as this NoRowException. It is not the standard `getSingleResult()` failure - that throws jakarta.persistence.NoResultException.","triggerScenarios":"`session.lock(entity, LockMode.PESSIMISTIC_WRITE)` (or `em.lock`/`em.refresh(PESSIMISTIC)`) where the row was deleted by a concurrent transaction before the `select ... for update` ran; pessimistic locking an entity whose row is excluded by @Where/@OnLoad filters or row-level security; a count query variant that returns no rows (e.g. grouped native count).","commonSituations":"Two users editing the same record, one deleting it while the other locks it; locking stale detached entities whose rows are gone; @Where-based soft-delete filters hiding the row; concurrent admin deletes racing background jobs that lock first.","solutions":["Re-check existence before locking: a fresh `em.find(...)` (which returns null when gone) before `em.lock(...)`","Catch NoRowException (and StaleObjectStateException for versioned entities) around the lock and treat it as a concurrent modification: reload or show a 'record no longer exists' outcome","For soft-deleted/filtered rows, verify the entity passes the current @Where/@Filters criteria before attempting to lock it","Prefer optimistic locking when concurrent deletes are common, since it fails gracefully at flush"],"exampleFix":"// before\nem.lock(employee, LockModeType.PESSIMISTIC_WRITE); // NoRowException if row deleted\n// after\nEmployee fresh = em.find(Employee.class, employee.getId());\nif (fresh == null) { throw new ObjectNotFoundException(employee.getId(), Employee.class.getName()); }\nem.lock(fresh, LockModeType.PESSIMISTIC_WRITE);","handlingStrategy":"try-catch","validationCode":"// Verify the row still exists before pessimistic locking\nEmployee fresh = em.find(Employee.class, id);\nif (fresh == null) return handleMissing(id); // row gone - do not lock","typeGuard":null,"tryCatchPattern":"try {\n    em.lock(managedEntity, LockModeType.PESSIMISTIC_WRITE);\n} catch (org.hibernate.sql.results.spi.NoRowException e) {\n    // unversioned entity: row vanished before SELECT ... FOR UPDATE ran\n    throw new ConcurrentDeletionException(id);\n} catch (jakarta.persistence.OptimisticLockException | org.hibernate.StaleObjectStateException e) {\n    // versioned entity: same race surfaced as stale object\n    throw new ConcurrentDeletionException(id);\n}","preventionTips":["Re-find the entity (fresh, in the same transaction) immediately before em.lock","Treat NoRowException from locking as a concurrent delete: reload, notify, or fail gracefully","For soft-deleted models check @Where criteria match before locking","Prefer optimistic locking in workflows where concurrent deletes are frequent"],"tags":["pessimistic-locking","concurrency","empty-result","no-row","locking","optimistic-locking"],"backgroundTag":"no-query-result","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}