Skip to content
Oracle Database

Oracle Error ORA-01403

no data found

Applies to: Oracle Database 19c, 21c, 23ai and 26ai (same wording)
Last technically reviewed 24 October 2026 on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally
The full message
ORA-01403: no data found
Other forms of this message
Raised in a stored function (with the stack under it)
ORA-01403: no data found
ORA-06512: at "SHOP.GET_CUSTOMER_EMAIL", line 6
Raised in an anonymous block in SQL*Plus or SQLcl
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4
Error code
ORA-01403
Product
Oracle Database
Versions
Oracle Database 19c, 21c, 23ai and 26ai (same wording)
Last reviewed
24 October 2026

What it means

ORA-01403 means a SELECT INTO in PL/SQL returned no rows, so there was no value to put into the variable; PL/SQL raised the predefined exception NO_DATA_FOUND.

A SELECT ... INTO statement must return exactly one row. Oracle's PL/SQL reference states that when it returns no rows, PL/SQL raises NO_DATA_FOUND immediately, before you can test SQL%NOTFOUND. If no handler catches it, the caller sees ORA-01403, normally with ORA-06512 lines that point to the SELECT INTO. Its opposite, more than one row, is ORA-01422.

NO_DATA_FOUND is the one predefined exception whose SQLCODE is positive (+100) rather than negative. Oracle's error reference describes it simply as "no data was found from the objects", which can also mean the end of a fetch. Ordinary SQL behaves differently: a plain SELECT that matches nothing just returns no rows, and an UPDATE or DELETE that matches nothing changes zero rows without an error.

Common causes

  • A SELECT INTO looks up a key that does not exist, such as an id from a URL, a deleted row or a value with different case or trailing spaces.
  • The WHERE clause is stricter than intended: an extra condition, a date compared with a time part, or a filter on a status the row does not have yet.
  • The row exists but is not visible to the session: it was inserted by another session that has not committed, or a security policy hides it.
  • The code assumes optional data is always there, such as a customer's default address or a configuration row.
  • The value in the WHERE clause is NULL, for example an unset parameter, and = NULL never matches any row.

Diagnose it

Read-only These queries only read the data dictionary (USER_, ALL_ and DBA_ views) and dynamic performance views (V$). They do not change data, privileges or settings, so they are safe to run first. DBA_ and V$ views need the matching privileges.

Find the SELECT INTO that raised it

The first ORA-06512 line under the error names the unit and line. Read the statement there.

SELECT line, text
FROM all_source
WHERE owner = 'SHOP'
  AND name = 'GET_CUSTOMER_EMAIL'
  AND line BETWEEN 3 AND 9
ORDER BY line;
What to look for

A SELECT ... INTO with a WHERE clause; note which variables or parameters it filters on.

Run the same query with the real value

SELECT COUNT(*) AS matches
FROM shop.customers
WHERE id = 4711;   -- the value the code was given
What to look for

0 confirms that no row matches. Then loosen one condition at a time to find which part of the WHERE clause excludes the row you expected.

Look for near misses in text keys

SELECT id, email, LENGTH(email) AS len
FROM shop.customers
WHERE UPPER(TRIM(email)) = UPPER(TRIM('Sara@Example.com'));
What to look for

A row here but not with an exact match means the stored value differs in case or has spaces; fix the data or compare consistently.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Handle NO_DATA_FOUND where "no row" is a valid answer

Changes schema

When a missing row is expected, catch NO_DATA_FOUND around that SELECT INTO and return or assign a defined value. Keep the handler close to the statement, in its own block, so it does not hide a NO_DATA_FOUND from somewhere else.

CREATE OR REPLACE FUNCTION shop.get_customer_email (p_id IN shop.customers.id%TYPE)
  RETURN shop.customers.email%TYPE
IS
  v_email shop.customers.email%TYPE;
BEGIN
  SELECT email INTO v_email FROM shop.customers WHERE id = p_id;
  RETURN v_email;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RETURN NULL;
END;
/

Use an aggregate so the query always returns one row

Changes schema

Oracle's reference suggests selecting COUNT(*), which returns one row even when nothing matches. MAX() works the same way for a single value: it returns NULL instead of raising the error. Use it only when at most one row can match, otherwise it hides duplicates.

CREATE OR REPLACE PROCEDURE shop.apply_discount (p_customer_id IN NUMBER)
IS
  v_rate NUMBER;
BEGIN
  SELECT MAX(rate) INTO v_rate
  FROM shop.customer_discounts
  WHERE customer_id = p_customer_id;

  IF v_rate IS NOT NULL THEN
    UPDATE shop.orders SET discount_rate = v_rate
    WHERE customer_id = p_customer_id AND status = 'OPEN';
  END IF;
END;
/

Use a cursor loop when zero or more rows are normal

Changes schema

A cursor FOR loop simply runs zero times when there are no rows, so no exception is raised. Use it when the code should process whatever rows exist.

CREATE OR REPLACE PROCEDURE shop.remind_open_orders (p_customer_id IN NUMBER)
IS
BEGIN
  FOR r IN (SELECT id FROM shop.orders
            WHERE customer_id = p_customer_id AND status = 'OPEN') LOOP
    shop.send_reminder(r.id);
  END LOOP;
END;
/

Raise a clear error when the row must exist

Changes schema

If a missing row means bad input, convert NO_DATA_FOUND into a message the caller can act on with RAISE_APPLICATION_ERROR, rather than returning NULL and failing later.

CREATE OR REPLACE PROCEDURE shop.ship_order (p_order_id IN NUMBER)
IS
  v_status shop.orders.status%TYPE;
BEGIN
  BEGIN
    SELECT status INTO v_status FROM shop.orders WHERE id = p_order_id;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      RAISE_APPLICATION_ERROR(-20010, 'Order ' || p_order_id || ' does not exist');
  END;
  -- continue with v_status
END;
/

Examples

Looking up a customer id that does not exist

Not reproduced here: no Oracle Database is installed for this site. The message text is from Oracle's error reference, and the ORA-06512 line follows the layout of Oracle's PL/SQL examples; the table and the line number are illustrative.

DECLARE
  v_email customers.email%TYPE;
BEGIN
  SELECT email INTO v_email FROM customers WHERE id = 4711;
END;
/
Expected result (documented format, not run)
ORA-01403: no data found
ORA-06512: at line 4

A trailing space in the key

Not reproduced here: no Oracle Database is installed for this site. The result shows the documented message; the names and line number are illustrative. With a VARCHAR2 column the comparison is exact, so the trailing space means no row matches.

DECLARE
  v_id customers.id%TYPE;
BEGIN
  -- the stored value is 'sara@example.com', the input has a trailing space
  SELECT id INTO v_id FROM customers WHERE email = 'sara@example.com ';
END;
/
Expected result (documented format, not run)
ORA-01403: no data found
ORA-06512: at line 5

How to prevent it

Decide for each SELECT INTO what should happen when there is no row, and write that down in code: a local handler, an aggregate, a cursor loop or a clear application error. Validate and normalise keys (trim, case) at the edge of the application.

Use SELECT INTO only for queries on a primary or unique key, or with an aggregate, so "exactly one row" is guaranteed or deliberately handled.

Common questions

How do I fix ORA-01403 no data found?

Find the SELECT INTO the ORA-06512 line points to, run its query with the same values to see why no row matches, then either fix the input or handle NO_DATA_FOUND where a missing row is a valid case.

Why does SQL%NOTFOUND not help after SELECT INTO?

Oracle documents that a SELECT INTO that returns no rows raises NO_DATA_FOUND immediately, before the next statement runs, so a later IF SQL%NOTFOUND test is never reached. Handle the exception instead.

Why is the SQLCODE for NO_DATA_FOUND +100?

It is the one predefined exception with a positive code: Oracle's list of predefined exceptions gives NO_DATA_FOUND the error code +100, while the message printed is ORA-01403.

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally. Messages and explanations follow Oracle's Database Error Messages reference; no Oracle Database was available, so the examples were not run locally.

Still stuck on an Oracle error?

Browse the full Oracle error library, or get hands-on help from an experienced SQL professional.