ABAP RAISE Statement: Throwing Exceptions (Class-based & Non-class-based)

Category
ABAP-Statements
Published
Author
Johannes

These statements are used to actively signal an exception situation during program execution. You typically do this when:

  • An error occurs that the current program unit (method, function module, form routine) cannot resolve itself.
  • An unexpected or invalid state is reached.
  • A specific business rule is violated.

Raising an exception interrupts the normal program flow at that point and passes control to a special error handling block (CATCH block for class-based exceptions) or to the caller (who then checks sy-subrc for non-class-based exceptions). This enables structured error handling.

There are two main types of exceptions and thus two RAISE variants:

1. Class-based Exceptions (Modern, Preferred!)

This is the standard way in modern, object-oriented ABAP. Exceptions here are objects of special exception classes (that inherit from CX_ROOT).

Syntax

" 1. Raise a new exception of a class:
RAISE EXCEPTION TYPE <exception_class>
[EXPORTING p1 = v1 p2 = v2 ...] " Pass parameters to constructor
[MESSAGE { <msg> " Message from object/interface
| ID <id> TYPE <t> NUMBER <n> [WITH v1 v2 v3 v4] " Message from T100
| oref->if_t100_message } ] " Message from another object
[USING MESSAGE]. " Use message from TEXTID
" 2. Re-raise an already existing exception object (e.g., in CATCH):
RAISE EXCEPTION <exception_object>.

How It Works

  1. An object of the specified <exception_class> is created. Values can be passed to the class constructor via EXPORTING to provide error details (e.g., the erroneous value, an ID).
  2. Optionally, a message from message maintenance (SE91) or another object can be linked to the exception via the MESSAGE addition (many exception classes implement the interface IF_T100_MESSAGE for this).
  3. The normal program flow is stopped.
  4. The system searches upward in the call stack for a TRY...CATCH block that can handle this exception class (or one of its superclasses).
  5. If a CATCH block is found, its code is executed.
  6. If no matching CATCH block is found, this leads to a runtime error (short dump).

Exception Classes

Created in SE24 and typically inherit from:

  • CX_STATIC_CHECK: Errors that could potentially already be detected at development time by syntax checking (but don’t have to be). Should normally be handled.
  • CX_DYNAMIC_CHECK: Errors that only occur at runtime but should be expected and handled by the program.
  • CX_NO_CHECK: Severe, unexpected errors where handling is not necessarily intended (often leads to dump if not explicitly caught).

Error Handling

The caller catches these exceptions with TRY. ... CATCH cx_... INTO DATA(lo_exc). ... ENDTRY.

2. Non-class-based Exceptions (Legacy)

This is the older method, used mainly in function modules and older methods.

Context: Only meaningful in procedures (function modules, methods, FORMs) that declare such exceptions in the EXCEPTIONS addition of their interface.

Syntax

RAISE <exception_name>.

How It Works

  1. Execution of the procedure is immediately terminated.
  2. The system sets the system field sy-subrc to a value that is assigned to this <exception_name> in the EXCEPTIONS addition of the caller (CALL FUNCTION ... EXCEPTIONS <exception_name> = value ...).
  3. The caller must check sy-subrc after the call to determine if this exception occurred.
  • Status: Considered obsolete for new developments, especially in the object-oriented context. Should only be used when older function modules require it.

Examples

1: Raise and Catch Class-based Exception

" Custom exception class (simplified)
CLASS zcx_division_by_zero DEFINITION INHERITING FROM cx_static_check.
ENDCLASS.
CLASS zcx_division_by_zero IMPLEMENTATION.
ENDCLASS.
START-OF-SELECTION.
DATA dividend TYPE i VALUE 10.
DATA divisor TYPE i VALUE 0.
DATA result TYPE f.
DATA lo_error TYPE REF TO zcx_division_by_zero.
TRY.
IF divisor = 0.
" Raise our own exception
RAISE EXCEPTION TYPE zcx_division_by_zero.
ELSE.
result = dividend / divisor.
WRITE: / 'Result:', result.
ENDIF.
CATCH zcx_division_by_zero INTO lo_error.
MESSAGE 'Error: Division by zero!' TYPE 'E'.
" Optional: Access attributes/methods of lo_error
ENDTRY.
WRITE / 'Program continues after TRY block.'.

2: Class-based Exception with Message

" Assumption: Message 010 in class ZMSG: 'Material &1 is not active.'
" Assumption: ZCX_MATERIAL_INACTIVE implements IF_T100_MESSAGE
DATA lv_matnr TYPE matnr VALUE 'M-INACTIVE'.
DATA lo_mat_error TYPE REF TO zcx_material_inactive.
TRY.
" ... Check reveals that material is inactive ...
RAISE EXCEPTION TYPE zcx_material_inactive
MESSAGE ID 'ZMSG' TYPE 'E' NUMBER '010' WITH lv_matnr.
CATCH zcx_material_inactive INTO lo_mat_error.
MESSAGE lo_mat_error->get_text( ) TYPE 'E'. " Get message from exception
ENDTRY.

3: Non-class-based Exception (Concept in Function Module)

FUNCTION Z_DO_SOMETHING.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" VALUE(INPUT) TYPE I
*" EXPORTING
*" VALUE(OUTPUT) TYPE I
*" EXCEPTIONS
*" INPUT_IS_ZERO " Declared exception
*"----------------------------------------------------------------------
IF input = 0.
RAISE input_is_zero. " raises the exception -> sy-subrc is set at caller
ELSE.
output = 100 / input.
ENDIF.
ENDFUNCTION.
" Calling program:
DATA result TYPE i.
CALL FUNCTION 'Z_DO_SOMETHING'
EXPORTING
input = 0
IMPORTING
OUTPUT = result
EXCEPTIONS
input_is_zero = 1 " Maps exception to sy-subrc = 1
OTHERS = 2.
IF sy-subrc = 1.
MESSAGE 'Input for Z_DO_SOMETHING was zero!' TYPE 'W'.
ELSEIF sy-subrc = 0.
WRITE: / 'Result:', result.
ENDIF.

Important Notes / Best Practice

  • Use class-based exceptions (RAISE EXCEPTION TYPE ...) for all new developments.
  • Define descriptive custom exception classes for specific error cases in your application. Derive them from CX_STATIC_CHECK or CX_DYNAMIC_CHECK.
  • Implement the interface IF_T100_MESSAGE in your exception classes to easily link them with message classes (SE91).
  • Pass relevant context information via the EXPORTING addition to the exception class constructor.
  • Catch exceptions specifically with TRY...CATCH...ENDTRY where they can be meaningfully handled. Let unhandleable exceptions consciously lead to a dump (especially CX_NO_CHECK-based ones).
  • Avoid RAISE <exception_name> in new code, unless interacting with very old function modules.