IBM i message

CEE9901: Application error (unhandled ILE exception)

CEE9901 is the generic "application error" message that IBM i sends when an error in an ILE program went unhandled all the way up to the program's control boundary. It doesn't describe the problem itself. The message it names, earlier in the job log, is the real cause.

Other names for this code

Also written as CEE9901 application error, MSGID CEE9901, CEE9901 unmonitored by, CEE0000, IBM i application error CEE9901.

What it means

CEE9901 belongs to ILE, the Integrated Language Environment that RPG IV, ILE COBOL, ILE C and ILE CL programs run in. When a program gets an exception it doesn't handle, ILE passes it up the call stack. Each caller gets a chance to deal with it. If it reaches a control boundary unhandled, it becomes a function check, CPF9999. If nothing handles the function check either, ILE treats the application as ended in error. It then sends the generic failure message CEE9901 to the caller of the control boundary.

A control boundary is where the ILE application begins. Typically that is the first ILE program in an activation group, such as an RPG program that a CL program calls. So the program that receives CEE9901 is usually the one that started the failing application. That might be a CL program, a menu or the command line.

The text of CEE9901 says which message went unmonitored, in which program, and at which statement. That message is the one to fix. A typical chain in the job log is the original error, such as MCH1202 or an RNX message from RPG, then CPF9999, then CEE9901.

Common causes

  • A data error in an ILE program, such as bad decimal data (MCH1202) or divide by zero, with no handler for it.
  • A pointer or parameter error, often MCH3601 when a program is called with fewer parameters than it expects.
  • An RPG program whose inquiry message was answered C or D. The program ended and the failure passed on to the control boundary.
  • A file or database error, such as a record lock or a missing file, that the program didn't check for.
  • An escape message sent on purpose by a lower program, for example CPF9898 with its own text, that nobody above it monitored.

How to find the problem

  1. Press F1 on CEE9901 to read its full text. Note the message ID it names, the program and the statement number.
  2. Run DSPJOBLOG and read up from CEE9901 to the first error. Everything after that first error is usually a consequence of it.
  3. Press F1 on the original message to see its help, which gives the cause in detail.
  4. Find the statement number in the compile listing of the program named, or debug it with STRDBG.

How to fix it

  • Fix the original error. CEE9901 disappears when the message it names stops happening.
  • Handle expected errors in the program where they occur, with MONITOR groups, a *PSSR subroutine, (E) extenders in RPG, or an ILE condition handler registered with CEEHDLR.
  • In the CL program that starts the application, monitor for the failure (MONMSG CEE9901, or CEE0000 for the whole range) so it can log the problem and end cleanly.
  • Send the full job log to the developers. The chain of messages up to CEE9901 tells them where to look.

IBM documentation

IBM Display Message Descriptions (DSPMSGD). Use the documentation for your installed release.

This link opens the relevant IBM reference library or lookup instructions. Match the complete code and your installed product release; it is not a code-specific review.

Report a correction to WND Software.

Questions

Is CEE9901 the real error?

No. It only says that an error went unhandled up to the control boundary. The message ID inside its text, and the first error above it in the job log, is the real cause.

What is the difference between CEE9901 and CPF9999?

CPF9999 is the function check raised when an error goes unhandled. CEE9901 comes later, when the function check is not handled either and ILE ends the application and reports it to the caller of the control boundary.

Can a CL program catch CEE9901?

Yes. It arrives as an escape message to the program that called the control boundary, so MONMSG MSGID(CEE9901) or MONMSG MSGID(CEE0000) after the CALL catches it.