ABAP Exception Handling Best Practices: Class-Based Exceptions
How to structure TRY/CATCH/CLEANUP blocks correctly, when to create your own exception classes, and why catching CX_ROOT everywhere is a mistake.
Published July 24, 2026
Advertisement
ABAP Exception Handling Best Practices: Class-Based Exceptions
Class-based exceptions replaced the old SY-SUBRC-checking style years ago, but a lot of code still uses them badly β catching too broadly, or not catching at all until a dump reaches production.
Catch the Most Specific Class You Can
" Avoid β hides which specific problem occurred
TRY.
lo_reader->read( iv_path ).
CATCH cx_root INTO DATA(lx_error).
" now what? we don't know if it was "file not found" or "permission denied"
ENDTRY.
" Prefer β handle what you can, let the rest propagate
TRY.
lo_reader->read( iv_path ).
CATCH cx_sy_file_open_mode INTO DATA(lx_open).
" specific recovery: maybe retry with a different mode
CATCH cx_sy_file_authority INTO DATA(lx_auth).
" specific recovery: surface a clear "no access" message
ENDTRY.
Catching CX_ROOT as your first and only branch throws away the information the exception hierarchy exists to give you. It's fine as a last branch, after specific ones, as a genuine catch-all β not as the only branch.
Use CLEANUP for Resource Release, Not Business Logic
TRY.
lo_connection = cl_my_connection=>open( iv_dest ).
lo_connection->send( iv_payload ).
CATCH cx_communication_error INTO DATA(lx_comm).
MESSAGE lx_comm->get_text( ) TYPE 'E'.
CLEANUP.
" Runs whether an exception was caught above or propagated past this TRY β
" always release the connection.
IF lo_connection IS BOUND.
lo_connection->close( ).
ENDIF.
ENDTRY.
The distinguishing feature of CLEANUP is that it runs even for exceptions not caught by this TRY block, on their way up the call stack. That's precisely why it's the right place for resource cleanup and the wrong place for anything that depends on knowing which exception occurred.
When to Create Your Own Exception Class
Create a custom CX_ class when:
- The caller needs to distinguish this failure from others programmatically (different
CATCHbranches). - You want to attach structured data to the exception (e.g. the specific field that failed validation), not just a text message.
CLASS cx_travel_validation DEFINITION INHERITING FROM cx_static_check.
PUBLIC SECTION.
DATA field_name TYPE string.
METHODS constructor
IMPORTING
field_name TYPE string
textid LIKE if_t100_message=>t100key OPTIONAL.
ENDCLASS.
Inherit from CX_STATIC_CHECK when the compiler should force callers to handle or declare the exception (checked exceptions) β this is the right default for business validation errors. Use CX_NO_CHECK only for genuinely unexpected, programming-error-style failures where forcing every caller to declare a CATCH would just add noise.
Don't Swallow Exceptions Silently
" Avoid β the exception disappears with no trace
TRY.
do_something( ).
CATCH cx_root.
ENDTRY.
An empty CATCH block is almost always a bug waiting to be invisible until it matters. At minimum, log it; ideally, decide explicitly whether the caller should know.
Use our ABAP Exception Handler Generator to scaffold a TRY...CATCH...CLEANUP block with the exception classes you choose already wired up, so you start from a structurally correct skeleton instead of typing it from memory each time.
Topics: