IBM Support

Job fails with MCH3402 - A deadly sin of ILE

Troubleshooting


Problem

Why does an IBM i job running an application fail with MCH3402

Symptom

Why does an IBM i job running an application fail with MCH3402.
Message . . . . :   Tried to refer to all or part of an object that no longer exists.
Message ID . . . . . . :   MCH3402       Severity . . . . . . . :   40      
Date sent  . . . . . . :   03/11/21      Time sent  . . . . . . :   12:58:37
Message type . . . . . :   Escape                                           
From . . . . . . . . . :   BIMBRA        CCSID  . . . . . . . . :   65535   
                                                                            
From program . . . . . . . . . :   QRNXIO                                   
  From library . . . . . . . . :     QSYS                                   
  From module  . . . . . . . . :     QRNXDBIO                               
  From procedure . . . . . . . :     _QRNX_DB_SETPOSN                       
  From statement . . . . . . . :     7                                      
                                                                            
To program . . . . . . . . . . :   QRNXIO                                   
  To library . . . . . . . . . :     QSYS                                   
  To module  . . . . . . . . . :     QRNXDBIO                               
  To procedure . . . . . . . . :     _QRNX_DB_SETPOSN                       
  To statement . . . . . . . . :     7           
                          
The From/To modules and procedure names seen above, might be different depending on the file operation that was in use by the application.

Cause

The following prelude is credited to Jon Paris and Susan Gantner who published a document in 2004 titled The Seven Deadly Sins of ILE.
First deadly sin: Allowing "real" ILE programs to run in the default activation group.
What do we mean by "real" ILE programs? These are programs that are created either via the CRTxxxMOD and CRTPGM commands or by specifying DFTACTGRP(*NO) to one of the CRTBNDxxx commands (where xxx is RPG or CL). Note that for the purposes of this discussion, programs created with the CRTBNDxxx default of DFTACTGRP(*YES) arent considered to be ILE programs; they are instead original program model (OPM)-compatible programs, and therefore arent bound by any of our ILE rules.
The default activation group (sometimes called DAG) is designed specifically for OPM programs and is the only activation group where these programs can run. You cannot directly request that your ILE programs run in the DAG, but if you specify *CALLER for the activation group parameter and subsequently call the program from an OPM program, your ILE program will run in the DAG. This is contrary to ILEs design (IBMs original intent was that ILE programs not be permitted to run in the DAG at all) and will eventually cause problems of some sort.

Second deadly sin: Using service programs in the DAG.
Many shops commit the first deadly sin and run their ILE programs in the DAG. If you happen to work in one of these shops, you can avoid some of the most serious problems by running your service programs in their own named activation group(s). Service programs are more prone to problems when running in the DAG, particularly if the Reclaim Resource (RCLRSC) command is run while the service program is active with files open. While RCLRSC is often used specifically to close open files, the command doesnt notify the service program logic that the files are closed. This leaves the application in a Catch 22 situation: The files are closed, but the procedures in the service program believe they are still open.

Diagnosing The Problem

This document presents a prototype to help illustrate how the MCH3402 message can surface.
The prototype consists of ILE RPG program TESTPGM1 and an ILE RPG service program TESTSRV1.
Both are compiled in the *CALLER activation group.  When called from the command line, they will then run in the OPM default activation group.
The program invokes a function named myfile, which resides in the service program.
The function simply reads the file, if a record is found, it updates a field with the current timestamp.
NOTE: The service program is not using LR to close the file. The program is using RETURN.
This is a common technique in large scale applications.  It saves the expense of closing and opening files and re-initializing program storage every time a function in the service program is invoked.
Use SQL to setup the library and database file
  • CREATE COLLECTION TESTLIB1
  • CREATE TABLE TESTLIB1/SOMEFILE (CLASS CHAR ( 5), STATUS NUMERIC ( 1,0), EFFDATE TIMESTAMP)
  • INSERT INTO TESTLIB1/SOMEFILE (CLASS, STATUS, EFFDATE) VALUES('FIRST', '1', current date) WITH NC
The database file is named SOMEFILE:
CLASS STATUS EFFDATE
FIRST 1 2021-03-11 12:58:16.867210
      
Create a source file in library TESTLIB1
CRTSRCPF FILE(TESTLIB1/MYSOURCE) RCDLEN(112)
Add source member TESTSRV1
       Ctl-Opt nomain;
       Dcl-F SOMEFILE DISK(*EXT) Usage(*input:*UPDATE)
                                   rename(SOMEFILE:SOMERCD);
       Dcl-PR myfile               Char(1);
          myflg                    Char(1);
       End-PR;

       Dcl-Proc myfile export;
       Dcl-PI myfile               Char(1);
          myflg                    Char(1);
       End-PI;

       Dcl-S rtnflg                Char(1);
          setll *start somefile;
          Read SOMERCD;
          If not %eof;
             EFFDATE = %timestamp(*sys);
             dsply (%timestamp(EFFDATE));
             Update SOMERCD;
          rtnflg = 'Y';
          elseif %eof;
           rtnflg = 'N';
          EndIf;
          Return rtnflg;
       End-Proc myfile;     
  • addlible testlib1
  • CRTRPGMOD   MODULE(TESTLIB1/TESTSRV1)   SRCFILE(TESTLIB1/MYSOURCE) SRCMBR(TESTSRV1)
  • CRTSRVPGM SRVPGM(TESTLIB1/TESTSRV1) EXPORT(*ALL) ACTGRP(*CALLER)
Add source member TESTPGM1
       Dcl-PR myfile               Char(1);
          myflg                    Char(1);
       End-PR;

       Dcl-S myflg                 Char(1);
          myflg  = myfile(myflg);
          Dsply ('File updated? ' +  myflg);
          Return;         
  • CRTRPGMOD MODULE(TESTLIB1/TESTPGM1) SRCFILE(TESTLIB1/MYSOURCE) SRCMBR(TESTPGM1)
  • CRTPGM PGM(TESTLIB1/TESTPGM1) BNDSRVPGM((TESTLIB1/TESTSRV1)) ACTGRP(*CALLER)
Run the program:
 
 > call testpgm1                           
   DSPLY  2021-03-11-14.58.27.695666       
   DSPLY  File updated? Y                 

Use DSPJOB option 14. Display open files, if active.
The database file SOMEFILE is open.
                                                                              
                       Member/    Record     File    I/O  ----Open---  Relative
 File       Library    Device     Format     Type   Count Opt Shr-Nbr   Record
 QDUI132    QSYS       QPADEV000H USRRCD     DSP       15 IO  NO               
 SOMEFILE   TESTLIB1   SOMEFILE   SOMEFILE   PHY        3 IO  NO              1
 QDDSPEXT   QSYS       QPADEV000H INFFMT     DSP       15 IO  NO               
 QDDSPOF    QSYS       QPADEV000H DETAIL2    DSP       12 IO  NO              

Now issue Reclaim Resource (RCLRSC) command.  While RCLRSC is often used specifically to close open files, the command does not notify the service program logic that the files are closed. This leaves the application in a Catch 22 situation: The files are closed, but the procedures in the service program believe they are still open.
 
When the program is called again following a RCLRSC , the result will be an MCH3402.
> call testpgm1                                                        
  Tried to refer to all or part of an object that no longer exists.    
  Call stack entry not found.                                          
  Exception recursion detected.                                        
  Application error.  *N unmonitored by *N at statement *N, instruction  X'4000'.                                                          

Joblog shows the message details:-
 
*NONE      Request                      03/11/21  15:07:50.665771  QMHGSD       QSYS        07CF     QCMD        QSYS        0195
                                     Message . . . . :  -rclrsc
*NONE      Request                      03/11/21  15:10:58.474699  QMHGSD       QSYS        07CF     QCMD        QSYS        0195
                                     Message . . . . :  -call testpgm1
MCH3402    Escape                  40   03/11/21  15:10:58.474898  QRNXIO       QSYS        *STMT    QRNXIO      QSYS        *STMT
                                     From module . . . . . . . . :   QRNXDBIO
                                     From procedure  . . . . . . :   _QRNX_DB_SETPOSN
                                     Statement . . . . . . . . . :   7
                                     To module . . . . . . . . . :   QRNXDBIO
                                     To procedure  . . . . . . . :   _QRNX_DB_SETPOSN
                                     Statement . . . . . . . . . :   7
                                     Message . . . . :   Tried to refer to all or part of an object that no longer
                                       exists.
                                     Cause . . . . . :   The most common cause is that a stored address to an
                                       object is no longer correct because that object was deleted or part of the
                                       object was deleted.
CPF2479    Escape                  40   03/11/21  15:10:58.475047  QMHSNDPM     QSYS        0C9E     QRNXIE      QSYS        *STMT
                                     To module . . . . . . . . . :   QRNXMSG
                                     To procedure  . . . . . . . :   SignalException
                                     Statement . . . . . . . . . :   20
                                     Message . . . . :   Call stack entry not found.
                                     Cause . . . . . :   Call stack entry _QRNI_NOMAIN, specified for the send,
                                       receive, move or delete message operation, could not be found in the call
                                       stack. Recovery  . . . :   Change the call stack entry name or be sure the
                                       specified entry is in the call stack when doing the requested operation.
CEE3201    Diagnostic              10   03/11/21  15:10:58.475163  QLEAWI       QSYS        *STMT    QRNXIE      QSYS        *STMT
                                     From module . . . . . . . . :   QLEDEH
                                     From procedure  . . . . . . :   Q LE leDefaultEh2
                                     Statement . . . . . . . . . :   72
                                     To module . . . . . . . . . :   QRNXERR
                                     To procedure  . . . . . . . :   _QRNX_UNEXP
                                     Statement . . . . . . . . . :   11
                                     Message . . . . :   Exception recursion detected.
                                     Cause . . . . . :   An unhandled exception occurred in an exception handler.
                                       Recovery  . . . :   Do not let an exception that occurs in your exception
                                       handler go unhandled.
CEE9901    Escape                  30   03/11/21  15:10:58.475218  QLEAWI       QSYS        *STMT    QCMD        QSYS        01C8
                                     From module . . . . . . . . :   QLETOOL
                                     From procedure  . . . . . . :   Q LE AWIRaise
                                     Statement . . . . . . . . . :   176
                                     Message . . . . :   Application error.  *N unmonitored by *N at statement *N,
                                       instruction X'4000'.
                                     Cause . . . . . :   The application ended abnormally because an exception
                                       occurred and was not handled.  The name of the program to which the
                                       unhandled exception is sent is *N *N . The program was stopped at the
                                       high-level language statement number(s) *N at the time the message was sent.
                                        If more than one statement number is shown, the program is an optimized ILE
                                       program.  Optimization does not allow a single statement number to be
                                       determined.  If *N is shown as a value, it means the real value was not
                                       available. Recovery  . . . :   See the low level messages previously listed
                                       to locate the cause of the exception.  Correct any errors, and then try the
                                       request again.

Resolving The Problem

To resolve the issue there are three options:
1: Remove the RCLRSC command call.
2: Close files every time you exit a program or service program, or modify the program so that when called with (say) no parameters it will close its files. This is actually quite a common technique when the other alternatives are not an option and a hard close on exit each time is too costly. The program would be called in this way prior to the RCLRSC.

3: Run the programs and service programs in named activation groups.

Document Location

Worldwide

Operating System

IBM i:All operating systems listed

[{"Line of Business":{"code":"LOB57","label":"Power"},"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SWG60","label":"IBM i"},"ARM Category":[{"code":"a8m0z0000000CHtAAM","label":"Programming ILE Languages"}],"ARM Case Number":"TS005105587","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"All Version(s)"}]

Document Information

Modified date:
08 March 2024

UID

ibm16428061