If you’re diving into the world of IBM i programming and stumbled across the term ERRHDLR, you might be scratching your head wondering what it is.
I was playing with an SQL Data Encryption routine earlier today and saw a code sample referencing ERRHDLR. “What is that?” I thought.
After much time digging through the IBM-i (this page intentionally left blank) documentation and community chats, I found some answers: ERRHDLR isn’t a standard built-in command or keyword in IBM i. ERRHDLR on IBM i is a system‑supplied error‑handling program used primarily by system APIs. It’s not something most developers call directly, which is why it feels a bit mysterious when you first bump into it.
ERRHDLR is an IBM‑supplied error handler used internally by the operating system to manage:
- Command processing errors
- Message routing
- Escape message handling
- Default error‑handling behavior when no user‑defined handler exists
It lives in QSYS and is invoked automatically by the command‑processing environment.
You’ll see references to it in:
- System dumps
- Job logs
- Stack traces
- Exception reports
For example, a job log might show:
Program . . . . . . . . . . . . . . . . : ERRHDLR
Library . . . . . . . . . . . . . . . . : QSYS
This simply means: “The system’s default error handler caught this condition.”
Why It Appears in Job Logs
You’ll see ERRHDLR when:
- A CL command fails and no custom MONMSG handles it
- A program sends an unmonitored escape message
- A system API throws an exception that bubbles up
- A command‑processing program (CPP) encounters an unexpected condition
It’s the OS saying:
“No user‑level handler caught this, so I’m stepping in.”
Should we use ERRHDLR?
Error handling is crucial in IBM i programming because it keeps your applications stable when things go sideways, like file not found or division by zero.
A better question might be – “Should we Ever Call ERRHDLR directly?”
No. It’s not a callable program or API. It’s part of the internal command‑processing architecture.
I cannot see ERRHDLR on my IBM-i system!
You’re not going crazy – you cannot see ERRHDLR with WRKOBJ because it is not a normal user‑visible program object.
This is one of those IBM i quirks where the system shows something in a call stack, but the underlying object is *not a standard PGM you can list, display, or interact with.
How should we do error handling in our CL and RPG code?
If you’re knee-deep in CL and RPG programming, you know that stuff happens. Files go missing, divisions hit zero, or some unexpected glitch pops up. The key is handling those errors gracefully, so your apps don’t crash and burn with that dreaded inquiry message screen.
Since we cannot simply call an IBM-i API like ERRHDLR directly, let’s have a quick high-level view of best practices for error handling in CL and RPG on IBM i.
If you want to override or customize error handling, you use:
MONMSGin CL*PSSRorMONITOR/ON-ERRORin RPGLE- SQL exception handlers (
DECLARE CONTINUE HANDLER) - Custom message handling via QMHSNDPM / QMHRCVPM
On IBM i, you handle errors differently depending on the language you’re using, such as CL or RPG. Let’s start with CL programs, since they’re the backbone for many system tasks.
In CL, the main tool for error handling is the MONMSG command. You place MONMSG right after the command that might fail. It monitors for specific message IDs and lets you execute alternative code if an error pops up. For example, if you’re copying a file with CPYF and it might not exist, you can do something like this:
CPYF FROMFILE(MYLIB/MYFILE) TOFILE(NEWLIB/NEWFILE)
MONMSG MSGID(CPF2802) EXEC(DO)
SNDUSRMSG MSG('File not found. Creating a new one.')
CRTDUPOBJ OBJ(MYFILE) FROMLIB(MYLIB) OBJTYPE(*FILE) TOLIB(NEWLIB) NEWOBJ(NEWFILE)
ENDDO
Here, CPF2802 is the message ID for “file not found.” The EXEC parameter runs the DO group to handle the error gracefully. You can monitor at the command level, program level, or even globally. It’s simple and effective for batch jobs or interactive sessions.
Now, shifting to RPG, which is where a lot of business logic lives on IBM i. RPG has evolved a ton, especially in free-format RPGLE. For modern error handling, use the MONITOR and ON-ERROR opcodes. These create a structured block to catch exceptions without crashing the program. Here’s a quick example:
MONITOR;
Total = Amount / Quantity; // Potential divide by zero
ON-ERROR 0103; // Specific status code for divide by zero
Dsply 'Oops, cannot divide by zero.';
Total = 0;
ON-ERROR; // Catch-all for other errors
Dsply 'Unexpected error occurred.';
ENDMON;
The MONITOR wraps the risky code. ON-ERROR handles specific status codes or all errors. You can find status codes in the program status data structure (PSDS) under *STATUS. For older fixed-format RPG, you might use the *PSSR subroutine, which is a program status subroutine that automatically kicks in on errors if defined.
There’s also the %ERROR built-in function in RPG with the ‘E’ extender on operations like READ or CHAIN. It returns ‘1’ if an error happened on the last I/O op. Like this:
CHAIN(E) Key MyFile;
If %ERROR();
Dsply 'Record not found or locked.';
Endif;
If ERRHDLR is a custom subroutine in your code, it might be called from these mechanisms to log errors, send alerts, or retry operations. For instance, in a *PSSR, you could EXSR ERRHDLR to jump to your custom logic.
One more thing for advanced setups. IBM i also has APIs like QMHRCVPM (Receive Program Message) for deeper error handling in mixed-language programs. These let you pull error details programmatically.
In summary, while ERRHDLR itself might be a bespoke name in your shop’s code, the core of error handling on IBM i revolves around MONMSG in CL and MONITOR/ON-ERROR or %ERROR in RPG. It keeps your apps robust and user-friendly.
Experiment with these in your next program, and you’ll see how they save your bacon.
New Blog idea – should I write and share a generic IBM-i error handler to capture errors, send them as messages to the user, log them in a file or data queue, maybe send to *SYSOPR?
Stay coding, IBM i Maestros.

