Skip to content
Oracle Database

Oracle Error ORA-20000

user-defined error (RAISE_APPLICATION_ERROR, ORA-20000 to ORA-20999)

Applies to: Oracle Database 19c, 21c, 23ai and 26ai (the text is written by the application)
Last technically reviewed 24 October 2026 on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally
The full message
ORA-20000: Order 1001 cannot be cancelled: it has already been dispatched
Other forms of this message
Any number from ORA-20000 to ORA-20999, chosen by the code that raised it
ORA-20145: Credit limit exceeded for customer 4711
With the stack showing where it was raised
ORA-20000: Order 1001 cannot be cancelled: it has already been dispatched
ORA-06512: at "SHOP.CANCEL_ORDER", line 11
ORA-06512: at line 2
Raised in a trigger
ORA-20000: Order 1001 cannot be cancelled: it has already been dispatched
ORA-06512: at "SHOP.ORDERS_BU", line 3
ORA-04088: error during execution of trigger 'SHOP.ORDERS_BU'
Error code
ORA-20000
Product
Oracle Database
Versions
Oracle Database 19c, 21c, 23ai and 26ai (the text is written by the application)
Last reviewed
24 October 2026

What it means

ORA-20000 (and every code up to ORA-20999) is an error raised on purpose by PL/SQL code with RAISE_APPLICATION_ERROR; the message text was written by that code's author, so it describes an application rule, not an Oracle failure.

Oracle reserves the range -20000 to -20999 for application errors. A stored procedure, function, trigger or package calls RAISE_APPLICATION_ERROR(error_code, message) with a number in that range and a message of up to 2048 bytes, and the caller receives it like any other Oracle error. Oracle's reference says only that RAISE_APPLICATION_ERROR was called, and its action is to correct the problem the message describes, or ask the application administrator or DBA.

That means the meaning is in the text after the number, and the person who can explain it is whoever wrote that code. The ORA-06512 lines under it show which unit and line raised it. Oracle's own supplied packages use the range too: for example the DBMS_UTILITY documentation lists ORA-20000 for COMPILE_SCHEMA when there are "insufficient privileges for some object in this schema".

The optional third argument decides what happens to errors that were already on the stack: TRUE puts the new error on top of them, while the default FALSE replaces the stack with the new error. With FALSE, an error raised in an exception handler hides the original cause, so the stack shows only the application message.

Common causes

  • A business rule in the application rejected the operation: a check in a procedure, package or trigger found invalid input or a disallowed state, and raised an error with a message for the user.
  • A trigger enforces a rule that a constraint cannot express (for example no changes to dispatched orders) and refused the DML.
  • An exception handler caught a lower-level error such as NO_DATA_FOUND and converted it into an application error with RAISE_APPLICATION_ERROR.
  • An Oracle-supplied package (owned by SYS) raised an error in this range, as some document in their exception lists.

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 code that raises this number

SELECT owner, name, type, line, text
FROM all_source
WHERE UPPER(text) LIKE '%RAISE_APPLICATION_ERROR%'
  AND text LIKE '%-20000%'
ORDER BY owner, name, line;
What to look for

Each RAISE_APPLICATION_ERROR call that uses -20000. Many applications reuse -20000 for everything, so also search for a fragment of the message text, and compare with the unit and line from the first ORA-06512 line.

Search by message text

SELECT owner, name, type, line, text
FROM all_source
WHERE owner = 'SHOP'
  AND UPPER(text) LIKE UPPER('%cannot be cancelled%')
ORDER BY name, line;
What to look for

The line that builds the message. The surrounding IF tells you exactly which condition was true.

Is it your code or an Oracle-supplied package?

SELECT owner, object_name, object_type
FROM all_objects
WHERE object_name = 'CANCEL_ORDER'   -- the unit named in the first ORA-06512 line
ORDER BY owner;
What to look for

An owner such as SYS means an Oracle-supplied package raised it: look the number up in that package's documentation. Any other owner is application code: ask its developers or read the source.

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.

Act on the message: it is the application's rule

Read-only

Read the text after the number and the code that raised it. Usually the right fix is to change the input or the order of operations (for example cancel before dispatch), not the database. Changing or removing the check is a decision for the application's owners.

Catch a specific application error by name in the caller

Changes schema

Give the number a name with PRAGMA EXCEPTION_INIT and handle just that case, so other errors still propagate. Oracle's PL/SQL reference shows this pattern for RAISE_APPLICATION_ERROR.

CREATE OR REPLACE PROCEDURE shop.try_cancel (p_order_id IN NUMBER, p_result OUT VARCHAR2)
IS
  already_dispatched EXCEPTION;
  PRAGMA EXCEPTION_INIT (already_dispatched, -20000);
BEGIN
  shop.cancel_order(p_order_id);
  p_result := 'CANCELLED';
EXCEPTION
  WHEN already_dispatched THEN
    p_result := 'TOO_LATE';   -- SQLERRM holds the full message if you need it
END;
/

When you raise application errors, use distinct numbers and keep the stack

Changes schema

Give each condition its own number (and document them in one package), so callers can handle them separately. When converting another exception inside a handler, pass TRUE as the third argument so the original error stays on the stack under yours.

CREATE OR REPLACE PROCEDURE shop.cancel_order (p_order_id IN NUMBER)
IS
  v_status shop.orders.status%TYPE;
BEGIN
  SELECT status INTO v_status FROM shop.orders WHERE id = p_order_id;
  IF v_status = 'DISPATCHED' THEN
    RAISE_APPLICATION_ERROR(-20000,
      'Order ' || p_order_id || ' cannot be cancelled: it has already been dispatched');
  END IF;
  UPDATE shop.orders SET status = 'CANCELLED' WHERE id = p_order_id;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RAISE_APPLICATION_ERROR(-20001, 'Order ' || p_order_id || ' does not exist', TRUE);
END;
/

Examples

An unhandled application error from a procedure

Not reproduced here: no Oracle Database is installed for this site. The procedure and message come from the RAISE_APPLICATION_ERROR example in Oracle's PL/SQL Language Reference; the ORA-06512 lines follow Oracle's documented stack layout, and the schema and line numbers are illustrative.

CREATE OR REPLACE PROCEDURE account_status (due_date DATE, today DATE) IS
BEGIN
  IF due_date < today THEN
    RAISE_APPLICATION_ERROR(-20000, 'Account past due.');
  END IF;
END;
/

BEGIN
  account_status(DATE '2026-07-01', DATE '2026-07-09');
END;
/
Expected result (documented format, not run)
ORA-20000: Account past due.
ORA-06512: at "SHOP.ACCOUNT_STATUS", line 4
ORA-06512: at line 2

Handling it by name with EXCEPTION_INIT

Not reproduced here: no Oracle Database is installed for this site. This is the documented example from Oracle's PL/SQL Language Reference, whose result is the line shown (printed by DBMS_OUTPUT, not raised as an error): the block handled the exception, so the caller sees no error.

DECLARE
  past_due EXCEPTION;
  PRAGMA EXCEPTION_INIT (past_due, -20000);
BEGIN
  account_status(DATE '2026-07-01', DATE '2026-07-09');
EXCEPTION
  WHEN past_due THEN
    DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20000)));
END;
/
Expected result (documented format, not run)
ORA-20000: Account past due.

How to prevent it

For application developers: keep a documented list of your -20xxx numbers and their meanings, write messages that say what was wrong and what to do, and include the key values (order id, customer id). Pass TRUE when converting another error so the cause is not lost.

For callers: handle the specific numbers you expect with EXCEPTION_INIT, show the message to the user where it is meant for them, and log the full stack for anything else.

Common questions

What does ORA-20000 mean?

It is not a built-in Oracle failure: some PL/SQL code called RAISE_APPLICATION_ERROR with that number and the message you see. Read the message, and use the ORA-06512 lines to find the code that raised it.

What is the difference between ORA-20000 and ORA-20001?

Only what the code that raised them chose. Any number from -20000 to -20999 can be used; applications usually give each kind of problem its own number so callers can tell them apart.

How long can the message be?

Oracle documents the RAISE_APPLICATION_ERROR message as a character string of at most 2048 bytes. Note that SQLERRM returns at most 512 bytes, so use DBMS_UTILITY.FORMAT_ERROR_STACK to log long messages in full.

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.