Problem solve Get help with specific problems with your technologies, process and projects.

Exception/error handling in RPG -- Part 2

It isn't always the case that all program or file errors are unexpected and the program should end. Learn what exception/error handling at the operational level means.

In last month's article I discussed exception/error handling at a global level in RPG, where a program shuts down in an orderly manner when it receives an unexpected error. But some of the errors may be expected. (Remember: one program's exception can be another program's rule.) It isn't always the case that all program or file errors are unexpected and the program should end. For example, you want your program to trap and handle exceptions for record locking, referential constraints, certain decimal data errors, etc.

So this month I will discuss exception/error handling at the operation level.

Trapping errors

Certain operation codes have the equivalent of a command level MONMSG in CL. That means the operation does not fail if it receives an error, and processing continues with the next operation. It is up to the program to determine whether there was an error and what to do about it.

You can trap an exception/error for certain operation codes by either specifying an error indicator in the low position or by using the E (Error) extender on the operation code, as shown in Figure 1. (I include the example with the indicator because you will come across it in legacy code but, of course, the preference is to use the E extender.) You check for an error by testing the indicator or the value of the %ERROR BIF.

C     KeyField      Chain     Customer                             90
C                   If        *In90

C     KeyField      Chain(E)  Customer
C                   If        %Error

       Chain(E) KeyField Customer;
       If %Error;

Figure 1: Examples of trapping exceptions/errors at the command level

The ability to trap errors does not apply to all to all operation codes, but it does apply to all file and "external related" operation codes (CALL, IN, OUT). The table below lists the operation codes eligible for an E extender or error indicator.


Which error?

Your program has trapped the error, but which error is it? The %STATUS BIF provides a five-digit status code that tells you what the error is. Program Status Codes are in the range 00100 to 00999 and File Status Codes are in the range 01000 to 01999. Status Codes in the range 00000 to 00050 are considered to be Normal (i.e. they are not set by an error condition).

Status codes correspond to RPG Run time messages file in QRNXMSG (e.g., Message RNQ0100 = Status Code 00100). You can view the messages using the command:


The below table lists some of the more commonly used Status Codes. Refer to the chapter on "File and Program Exception/Errors" in the ILE RPG Reference manual for a full list of status codes.

00100  Value out of range for string operation
00102  Divide by zero
00112  Invalid Date, Time or Timestamp value.
00121  Array index not valid
00122  OCCUR outside of range
00202  Called program or procedure failed
00211  Error calling program or procedure
00222  Pointer or parameter error
00401  Data area specified on IN/OUT not found
00413  Error on IN/OUT operation
00414  User not authorized to use data area
00415  User not authorized to change data area
00907  Decimal data error (digit or sign not valid)
01021  Tried to write a record that already exists (file being used has unique keys and key is duplicate, or attempted to write duplicate relative record number to a subfile).
01022  Referential constraint error detected on file member.
01023  Error in trigger program before file operation performed.
01024  Error in trigger program after file operation performed.
01211  File not open.
01218  Record already locked.
01221  Update operation attempted without a prior read.
01222  Record cannot be allocated due to referential constraint error
01331  Wait time exceeded for READ from WORKSTN file.

Figure 2 shows an example of checking for another program having a lock on a record that your program is trying to get for update. The E extender traps the error, which is checked for on the next line using the %ERROR BIF. The error is handled if the status is 1218, otherwise your program falls back on the trusty *PSSR routine. Note the use of the file name with the %STATUS BIF to enable you to differentiate between the current statuses of different files.

       Chain(E) KeyField Customer;
       If %Error;
           If %Status(Customer) = 1218;                                                                              
         // Handle the record lock                                                                           
               ExSR *PSSR;                                                                                       

Figure 2: Checking for record already locked.

What about the other operation codes?

V5R1 of OS/400 saw the introduction of a MONITOR group. It allows you to monitor a number of statements for potential errors, as opposed to doing them one at a time. In structure it is quite similar to a SELECT group. The boundary is set by a MONITOR and an ENDMON operation. The MONITOR operation is followed by the lines of code that you want to monitor. The code is followed by a set of ON-ERROR operations that indicate the error conditions that are being monitored along with the appropriate code to handle the error. If there is no error in the code, control branches to the ENDMON operation when the first ON-ERROR operation is reached. If an error is detected in the code, control branches to the ON_ERROR operations which are processed in sequence -- working in the same way as WHEN operations in a SELECT group. When the code for an ON-ERROR segment has been processed, control passes to the ENDMON operation. Monitor groups may be nested.

Figure 3 shows a simple example of a Monitor group. There are several errors that may occur for these few lines of code. There may be an error on the READ operation: The monitor handles a file not open error separately from other file errors by having an ON-ERROR operation for status 1211 and an ON-ERROR operation for all other file errors (*FILE). The next ON-ERROR operation traps potential string errors (status 100) and array index errors (121). The final ON-ERROR operation traps all other errors.

           Read Customer;
           If Not %EOF;
               Line1 = %SUBST(Line(i): %SCAN('***': Line(i)) + 1);
       On-Error 1211;
  //          ... handle file-not-open
       On-Error *FILE;
  //          ... handle other file errors
       On-Error 00100 : 00121;
  //          ... handle string error and array-index error
  //          ... handle all other errors

Figure 3: Using a Monitor group

A Monitor group also applies to code executed in called subroutines. The Monitor group shown in Figure 4 works the same as the one shown in Figure 3. The same cannot be said for subprocedures; if the code in a subprocedure fails, you can trap the error on the call to the subprocedure by checking for status 202.

           ExSR SubEx;
       On-Error 1211;
  //          ... handle file-not-open
       On-Error *FILE;
  //          ... handle other file errors
       On-Error 00100 : 00121;
  //          ... handle string error and array-index error
  //          ... handle all other errors

       BegSR SubEx;
           Read Customer;
           If Not %EOF;
               Line1 = %SUBST(Line(i): %SCAN('***': Line(i)) + 1);

Figure 4: Using a Monitor group to monitor code in a subroutine

There's more

If you need more information about the status of a program or any of the files in the program, you can make use of special data structures. The program status data structure provides information about the program, and file information data structures provide information about the files being used in the program.

A program status data structure is identified by an SDS definition, and there can be only one per program. A file information data structure is associated with a file using an INFDS keyword on the F Spec, and it must be unique for a file. These data structures contain an immense amount of information about the program and files and not just information relating to errors. Again, refer to the chapter on "File and Program Exception/Errors" in the ILE RPG Referencefor a full list of the contents of the data structures.

Figure 5 shows an example of a program status and a file information data structure. Keywords may be used in place of from/to positions for certain information, such as the procedure name. The MSGID fields identify the relevant CPF or MCH error message received by the program. The MIN_RRN field identifies the RRN of the subfile record at the top of the screen when it was input (which is a lot more dependable then using SFLCSRRRN). PROCEDURENAME identifies the name of the program and USERPROFILE identifies the user profile in the job id.

FDisplay   CF   E             WorkStn                   
F                                     InfDS(DisplayInfDS) 
F                                     InfSR(*PSSR)        

D DisplayInfDS    DS                  NoOpt  
D                                     Qualified
D  MsgId                 40     46      
D  Min_RRN              378    379I 0          

D ProgramStatus  SDS                  NoOpt          
D                                     Qualified
D  ProcedureName    *Proc    
D  MsgId                 46     52      
D  UserProfile          254    263        

Figure 5: Program status and file information data structures

Then there is ILE

The ILE environment introduces a couple of considerations for error handling.

The first of these is percolation, where exceptions/errors are percolated to the previous call stack entry until the message is handled or until an AG boundary is met as opposed to the program failing and immediately displaying an error message. In other words, if the program does not handle an error, it is "percolated" back up the call stack.

The second is that you can write your own exception/error handler, which you register in your programs using the CEEHDLR API.

Refer to Chapter 9 of the ILE Concepts manual for further information.

Priority of handlers

This is the priority of the error handlers in RPG IV:

  • 'E' Operation extender (or Error Indicators)
  • Monitor groups
  • File Exception error subroutine
  • ILE Condition handler
  • Program Exception Error Subroutine (*PSSR)
  • RPG default error handler

In the end . . .

I started the previous article by stating that I have always believed that users should never, ever, see a CPF message issued from an RPG program.

I hope that this article and the preceding article have demonstrated how you can ensure your users and your help desk are saved a lot of frustration and irritation.

About the author: Paul Tuohy is CEO of ComCon, an iSeries consulting company.
He is the author of Re-Engineering RPG Legacy Applications and is one of the quoted
industry experts in the IBM Redbook "Who Knew You Could Do That With RPG IV?"


Dig Deeper on iSeries CL programming