Thursday, October 10, 2013

MONITOR for errors in RPG

I am sure all IBM i (AS400) programmers are familiar with the MONMSG command in CL to capture exceptions (errors) and stop an error message from interrupting the program. You can do the same in your RPG code using what IBM calls the "monitor group".

The "monitor group" consists of the MONITOR, ON-ERROR, and ENDMON operation codes. When an error occurs within the "monitor group" it can be handled by using specific status codes, or by the use of one of the following special values *PROGRAM, *FILE, *ALL. *PROGRAM handles all of the program related status codes, 100 - 999. *FILE handles all of the file related errors, 1000 - 9999. *ALL, as it suggests, handles all errors, and is the default for the the ON-ERROR operation.

The basic layout of a "monitor group" is as follows:

01     monitor ;
03     on-error <status-code or special-value> ;
05     on-error <another-status-code or special-value>;
07     on-error ;
09     endmon ;

The "monitor group" starts with the MONITOR operation code, line 1.

The statements that appear between the MONITOR and the first ON-ERROR is what is being monitored. This could be more than one line of code.

The ON-ERROR on line 3 could be for a specific status code or one of the special values mentioned above. If that condition is true line 4 would be executed. Status codes are numeric fields, therefore, code 00100 can be typed as 100.

In this example if the first ON-ERROR was not true the next one, line 5, is tested.

The last ON-ERROR is what I call the "catch all", i.e. if it is an error that is not handled by one of the above ON-ERROR this one catches it. Think of it like the OTHER operation in a select group or the final ELSE in an IF-ELSEIF group.

At the end of the "monitor group" is the ENDMON operation code.

Warning:   If an operation code uses the 'E' operation extender the error is handled by that rather than the "monitor group".

Rather than list all of the status codes in this post I am going to refer you to the page on IBM's website for IBM i 7.1.

Below are some examples. The first is how I could capture a "divide by zero" error, program status code 00102:

01     monitor ;
02       eval(h) Result = Nbr1 / Nbr2 ;
03     on-error 102 ; 
04       Result = 0 ;
05       Error = 'Divide by 0' ;
06     endmon ;

What is wrong with the example below?

01     monitor ;
02       open(e) FILE ;
03     on-error *file ; 
04       Error = 'File not opened' ;
06     endmon ;

As the OPEN operation code has the 'E' operation extender the "monitor group" does not monitor the message. If the operation extender is removed then the "monitor group" is executed, see below:

01     monitor ;
02       open FILE ;
03     on-error *file ; 
04       Error = 'File not opened' ;
06     endmon ;

The example below shows that there can be multiple status codes on the same ON-ERROR, lines 5 and 7:

01     monitor ;
02       in *lock DataArea ;
03       DataArea += 1 ;
04       out DataArea ;
05     on-error 401 : 411 ;
06       Error = 'Data Area not found' ;
07     on-error 412 : 413 ;
08       Error = 'Data Area update error' ;
09     endmon ;

You can learn more about these operatin codes on the IBM web site:


This article was written for IBM i 7.1, and it should work with earlier releases too.


  1. Its good to wrap your main procedure with this.

  2. I no longer recommend the use of *ALL (or even *FILE etc. normally). Since I believe in using a generic catch-all PSSR I find it preferable to monitor only for those exceptions that I can do something sensible about (div by zero or numeric overflow being good examples) and leave the PSSR to handle anything that will cause a crash and burn scenario.

  3. Instead of inventing a message text, it is possible to retrieve the message text that is send by an escape message using the Program Status Structure.
    The error message is returned in position 91-170.

    1. You are correct & it makes it nicer to use IBM's message text for a lot of errors. Below is how I could code it using the external data structure Program Status Data Structure I describe in the post Externally described Data Structures.

      D PgmDs ESDS extname(RPG4DS) qualified
      D c S 1 0
      D b S 1 0 inz(1)
      D a S 1 0 inz(0)
      D Error S 80
      monitor ;
      c = b / a ;
      on-error ;
      Error = PgmDs.RtvExcptDt ;
      endmon ;

    2. Question regarding pos 91-170: is there information you are required to supply. In other words would the text be something like Object &1 not found in Library &2 ?

    3. You get the who string with the object name & library in it.

  4. good stuff.. thanks

  5. The MONITOR block should not result in putting more effort in coding error analysis than trying to avoid a error situation by proper coding.
    I agree with Jon that MONITOR usage should be restricted to datatype-conversions and similar error-prone tasks that are else hard to trap. It's definitely not meant to be a general make-my-messy-code-work tool. Regarding file handling, I cannot see any advantage over %Error.

  6. Alvaro Roberto MeoƱo WongOctober 11, 2013 at 12:37 PM

    ery interesting never had used since the version that is currently working AS400 version 5.7, there are commands that one ignores or does not take them much importance as the CL and RPG native is very extensive.

  7. This opcode sounds great. Why did it take so long to get it?

  8. Just a question.

    Where I can see the meaning of codes that I can use in MONITOR?

  9. There are links to all the possible codes used by the MONITOR about half way down the post.

  10. In some ways MONITOR is even better than CL's MONMSG. With MONMSG, you either monitor a single statement or the whole CL program. But with MONITOR, you can define the precise block of code you want to monitor for errors, giving you better control.

    Java programmers will note MONITOR's similarity to Java's "try ... catch" construct.

    Things I sometimes MONITOR for:
    1. Arithmetic overflow, say, on incrementing a counter or calculating a total or rate
    2 .Invalid decimal data (fixed-format MONITOR in conjunction with an alpha-to-numeric MOVE)

    One place I've learned not to MONITOR, though: I/O errors. The INFDS and PSDS don't always get updated if MONITOR catches the error first. If you need that info, use the (E) op-code extender and IF %ERROR instead.

    1. Simon, thought you might need the error message detail I get on my Monitor.

      Message ID . . . . . . : RNX0112 Severity . . . . . . . : 50
      Message type . . . . . : Escape
      Date sent . . . . . . : 02/20/17 Time sent . . . . . . : 14:41:47

      Message . . . . : Date, Time or Timestamp value is not valid.
      Cause . . . . . : The Date, Time or Timestamp value is not valid. Some
      examples of values which are not valid are:
      -- A date of 1994/02/31, which is not possible.
      -- A time of 01/03:04, which does not have correct separators.
      Recovery . . . : Correct the value of the Date, Time or Timestamp field.

      And this:
      Message ID . . . . . . : RNX0112 Severity . . . . . . . : 50
      Date sent . . . . . . : 02/20/17 Time sent . . . . . . : 14:41:47
      Message type . . . . . : Escape
      From . . . . . . . . . : AOS CCSID . . . . . . . . : 65535

      From program . . . . . . . . . : QRNXIE
      From library . . . . . . . . : QSYS
      From module . . . . . . . . : QRNXMSG
      From procedure . . . . . . . : SignalException
      From statement . . . . . . . : 26

      Any ideas would be appreciated.
      Thanks, GL

  11. I wouldn't recommend using this much at all. If your monitor block errors then it writes that error to the job log, even though it was an error you were expecting and handled. This adds overhead and makes the job log confusing.
    The similarities with Java exceptions are slim. You can do SO much more with exceptions.

  12. Hi Simon,
    I have an issue with a Monitor command. Users can enter dates in character fields 010117. I monitor for it and basically I end up with 01/01/17. It works great, my file updates are fine...but, if the first monitor hits an on-error to continue with the second monitor IBM tosses me out a message to the screen.
    Date, Time or Timestamp value is not valid.
    This shows up on my display message line even though I handled the dates and I no longer have an error. I tried adding *program and *all to my on-error line with no success. Any idea what I'm doing wrong? Not sure if you can follow this since I'm using some internal service programs for our message handling and screen attributes.... Thanks, Geri

    wkDate = #WEffDate; // wkdate is 8char, #WeffDate is
    wkDate = %char(%date(WkDate:*mdy0):*mdy/);
    #wEffDate = wkDate;
    on-error ; // maybe it's already in display date format?
    wkDate = %char(%date(wkDate:*mdy/):*mdy/);
    #wEffDate = wkDate;
    #WMSG = 'Invalid Date. MMDDYY or MM/DD/YY';
    Field = '#WEFFDATE';
    MS_SendPMsg(msgId: msgFile: #wmsg: msgType: msgInvoc);
    DI_GetRowCol(diHnd:'WND01': Field: #CsrRw: #CsrCl);
    aEffDate = red;
    $error = *on;

    1. My understanding of the MONITOR operation code is that it does not stop an error from happening, it stops the error from breaking out and taking down the program.

  13. After MONITOR end endmon can program continue


To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.