Chapter 16: Declaratives and Exception Handling -- Key Takeaways

Chapter Summary

Robust error handling is what separates production-quality COBOL programs from programs that work only under ideal conditions. This chapter explored the mechanisms COBOL provides for detecting, reporting, and recovering from errors at runtime, with a focus on the DECLARATIVES section and the USE statement, file status codes, and inline exception-handling phrases. Together, these features allow a COBOL program to anticipate failures, respond to them gracefully, and either continue processing or terminate in a controlled manner with meaningful diagnostic information.

The DECLARATIVES section, coded at the very beginning of the PROCEDURE DIVISION before any other sections or paragraphs, contains one or more USE procedures that the runtime invokes automatically when specific error conditions occur. The USE AFTER STANDARD ERROR PROCEDURE statement associates an error-handling section with a specific file, a file category (INPUT, OUTPUT, I-O, EXTEND), or all files. When an I/O error occurs on a covered file, the runtime transfers control to the appropriate USE procedure after the I/O statement completes, giving the program an opportunity to log the error, attempt recovery, or set flags that control subsequent processing. The USE BEFORE REPORTING declarative, associated with Report Writer, fires before a report group is generated, allowing the program to modify field values or suppress the group entirely.

The chapter also covered inline exception-handling phrases that are coded directly on I/O and arithmetic statements: INVALID KEY and NOT INVALID KEY for indexed and relative file operations, AT END and NOT AT END for sequential reads, ON SIZE ERROR and NOT ON SIZE ERROR for arithmetic overflow and division by zero, and ON OVERFLOW for STRING and UNSTRING operations. File status codes were examined in depth as the primary diagnostic mechanism for file I/O, with the two-byte status field providing both broad categories (first byte) and specific conditions (second byte) that tell the program exactly what happened after every file operation. We discussed error recovery patterns including retry logic, alternate processing paths, graceful degradation, and controlled program termination with meaningful return codes.

Key Concepts

  • The DECLARATIVES section must appear at the very beginning of the PROCEDURE DIVISION, before any non-declarative sections, and is delimited by END DECLARATIVES.
  • Each declarative section contains a USE statement followed by procedural code that executes when the specified condition occurs.
  • USE AFTER STANDARD ERROR PROCEDURE ON file-name associates an error handler with a specific file, invoked automatically after any I/O error on that file.
  • USE AFTER STANDARD ERROR PROCEDURE ON INPUT/OUTPUT/I-O/EXTEND associates an error handler with all files opened in the specified mode.
  • USE BEFORE REPORTING report-group-name fires before the named report group is generated by Report Writer, allowing last-moment modifications or suppression of the group.
  • File status codes are two-byte values set by the runtime after every I/O operation, stored in the data item named in the FILE STATUS clause of the SELECT statement.
  • The first byte of the file status code indicates the broad outcome: "0" for success, "1" for AT END, "2" for INVALID KEY, "3" for permanent error, "4" for logic error, and "9" for implementation-defined conditions.
  • The second byte provides specific detail: for example, "00" is successful completion, "10" is end of file, "23" is record not found, "35" is file not found on OPEN, and "22" is duplicate key.
  • INVALID KEY fires on indexed and relative file READ, WRITE, REWRITE, and DELETE when the key condition is not met (record not found, duplicate key, key out of sequence).
  • NOT INVALID KEY fires when the I/O operation completes successfully, providing a clean separation between the success and failure paths within the same statement.
  • AT END fires on a sequential READ when there are no more records to retrieve, signaling end-of-file.
  • ON SIZE ERROR fires on ADD, SUBTRACT, MULTIPLY, DIVIDE, and COMPUTE when the result exceeds the capacity of the receiving field or when division by zero occurs.
  • NOT ON SIZE ERROR fires when the arithmetic operation completes successfully without overflow or division by zero.
  • ON OVERFLOW fires on STRING and UNSTRING when the receiving field is too small to hold the result or when the pointer value is out of range.
  • The DECLARATIVES USE procedure receives control after the I/O statement has completed and the file status code has been set, allowing the procedure to examine the status and take appropriate action.
  • Error recovery patterns include retry logic (re-executing the failed operation after corrective action), alternate path processing (switching to a backup file or default value), and controlled termination (closing files, writing diagnostic output, and returning a nonzero return code).

Common Pitfalls

  • Placing DECLARATIVES after regular sections: The DECLARATIVES section must be the very first thing in the PROCEDURE DIVISION. Placing it after other sections or paragraphs causes a compilation error.
  • Not checking file status after every I/O operation: Relying solely on INVALID KEY and AT END phrases misses many error conditions, including file-not-found on OPEN (status 35), permanent I/O errors (status 30), and logic errors like reading a file that is not open (status 41). Always check the file status field.
  • Falling through a USE procedure: A USE procedure should end with a deliberate action such as setting an error flag, performing a recovery routine, or preparing for program termination. If the procedure simply falls through with no action, the program continues as if the error never happened, potentially corrupting data.
  • Confusing INVALID KEY with file status checking: INVALID KEY only fires for specific key-related conditions on indexed and relative files. It does not fire for permanent I/O errors, file-not-found, or other non-key-related failures. File status checking covers all conditions.
  • Not testing for the specific file status value: Checking only whether the status is "00" (success) or not is insufficient for meaningful error handling. Different non-zero status values require different responses: a "10" (end of file) is normal, a "23" (record not found) may be recoverable, and a "30" (permanent error) usually is not.
  • Ignoring ON SIZE ERROR on arithmetic statements: When an arithmetic result overflows its receiving field, COBOL does not raise an error by default; it silently truncates the result. The ON SIZE ERROR phrase is the only way to detect this condition, and omitting it in financial calculations can produce silently incorrect amounts.
  • Multiple USE procedures for the same file: If more than one USE procedure could apply to the same file (for example, one for the specific file name and one for all INPUT files), the more specific procedure takes precedence. Misunderstanding this precedence can lead to unexpected behavior when only the general handler executes.
  • Attempting to perform I/O in a USE procedure on the file that caused the error: Executing I/O operations on the same file within its own USE AFTER ERROR procedure causes undefined behavior. The USE procedure should only examine the file status, log the error, and set flags for the main program to act upon.

Quick Reference

      * FILE STATUS clause in SELECT
           SELECT CUST-FILE
               ASSIGN TO "CUSTDATA"
               ORGANIZATION IS INDEXED
               ACCESS MODE IS DYNAMIC
               RECORD KEY IS CUST-ID
               FILE STATUS IS WS-CUST-STATUS.

       01  WS-CUST-STATUS        PIC XX.

      * DECLARATIVES section
       PROCEDURE DIVISION.
       DECLARATIVES.
       CUST-FILE-ERROR SECTION.
           USE AFTER STANDARD ERROR PROCEDURE ON CUST-FILE.
       CUST-FILE-ERROR-PARA.
           DISPLAY "I/O ERROR ON CUST-FILE"
           DISPLAY "FILE STATUS: " WS-CUST-STATUS
           EVALUATE WS-CUST-STATUS
               WHEN "35"
                   DISPLAY "FILE NOT FOUND"
                   MOVE "Y" TO WS-FATAL-ERROR
               WHEN "30"
                   DISPLAY "PERMANENT I/O ERROR"
                   MOVE "Y" TO WS-FATAL-ERROR
               WHEN OTHER
                   DISPLAY "UNEXPECTED ERROR"
                   MOVE "Y" TO WS-FATAL-ERROR
           END-EVALUATE.
       END DECLARATIVES.

      * Main processing with inline exception handling
       MAIN-SECTION SECTION.
       MAIN-PARA.
           OPEN I-O CUST-FILE
           IF WS-CUST-STATUS NOT = "00"
               DISPLAY "OPEN FAILED: " WS-CUST-STATUS
               STOP RUN
           END-IF

      * READ with INVALID KEY / NOT INVALID KEY
           MOVE "C12345" TO CUST-ID
           READ CUST-FILE
               INVALID KEY
                   DISPLAY "CUSTOMER NOT FOUND: " CUST-ID
               NOT INVALID KEY
                   PERFORM PROCESS-CUSTOMER
           END-READ

      * Checking file status explicitly
           IF WS-CUST-STATUS NOT = "00"
               AND WS-CUST-STATUS NOT = "23"
               DISPLAY "UNEXPECTED READ ERROR: "
                   WS-CUST-STATUS
               PERFORM ERROR-CLEANUP
           END-IF

      * Arithmetic with ON SIZE ERROR
           DIVIDE WS-TOTAL-AMOUNT BY WS-NUM-ITEMS
               GIVING WS-AVERAGE-AMOUNT
               ON SIZE ERROR
                   DISPLAY "ARITHMETIC OVERFLOW/ZERO DIVIDE"
                   MOVE 0 TO WS-AVERAGE-AMOUNT
               NOT ON SIZE ERROR
                   CONTINUE
           END-DIVIDE

      * Common file status codes reference:
      * "00" - Successful completion
      * "02" - Duplicate alternate key (success)
      * "10" - End of file (AT END)
      * "22" - Duplicate primary key on WRITE
      * "23" - Record not found on READ/DELETE
      * "35" - File not found on OPEN
      * "30" - Permanent I/O error
      * "41" - OPEN on already-open file
      * "42" - CLOSE on already-closed file
      * "43" - DELETE/REWRITE without prior READ
      * "46" - Sequential READ without positioning
      * "47" - READ on file not opened INPUT/I-O
      * "48" - WRITE on file not opened OUTPUT/I-O/EXTEND

What's Next

Chapter 17 introduces Subprograms and the CALL Statement, which are the foundation of modular programming in COBOL. You will learn how to break large programs into smaller, reusable subprograms using the CALL statement with BY REFERENCE, BY CONTENT, and BY VALUE parameter-passing mechanisms. The LINKAGE SECTION, the USING clause on both the CALL statement and the PROCEDURE DIVISION header, and the difference between static and dynamic calls will be covered in detail. These modular programming techniques are essential for building maintainable enterprise systems where common routines such as error handlers, data validation modules, and business rule engines are shared across multiple calling programs.