Every COBOL program that runs in production will eventually encounter an error. A file will be missing. A disk will fill up. A record will contain unexpected data. An arithmetic operation will produce a number too large for its destination field. A...
In This Chapter
- Introduction: When Things Go Wrong in Production
- 16.1 The DECLARATIVES Section
- 16.2 File Status Codes: Complete Reference
- 16.3 Inline Exception Handling: ON SIZE ERROR
- 16.4 ON OVERFLOW for String Operations
- 16.5 INVALID KEY for File Operations
- 16.6 AT END for Sequential Reads
- 16.7 COBOL 2002 RAISE and RESUME: Structured Exception Handling
- 16.8 IBM Language Environment Condition Handling
- 16.9 Return Codes and Program Communication
- 16.10 Common Abend Codes
- 16.11 Error Logging Patterns
- 16.12 Defensive Programming Techniques
- 16.13 Production Error Handling Framework
- 16.14 VSAM Extended Status Codes
- 16.15 Exception Handling in Called Programs
- 16.16 Exception Handling Across Platforms
- 16.17 Error Handling in Multi-Program Systems
- 16.18 Best Practices Summary
- Summary
- Exercises
Chapter 16: Declaratives and Exception Handling
Introduction: When Things Go Wrong in Production
Every COBOL program that runs in production will eventually encounter an error. A file will be missing. A disk will fill up. A record will contain unexpected data. An arithmetic operation will produce a number too large for its destination field. A key will not be found in an indexed file. The question is not whether errors will occur, but whether your program is prepared to handle them gracefully.
In many modern programming languages, exception handling was added as an afterthought -- bolted on years after the language was designed. COBOL, by contrast, has had error-handling mechanisms since its earliest standards. The DECLARATIVES section, introduced in COBOL-68, provides a way to intercept I/O errors before they crash a program. The imperative scope terminators introduced in COBOL-85 brought inline error handling with phrases like ON SIZE ERROR, AT END, and INVALID KEY. The COBOL 2002 standard added structured exception handling with RAISE and RESUME, bringing COBOL closer to the try/catch model familiar in Java and C#.
On IBM mainframes, the Language Environment (LE) condition handling model provides an additional layer of error management that operates beneath the COBOL language level, intercepting hardware and software exceptions before they become program-terminating abends. Understanding this model is essential for any COBOL programmer working in a z/OS environment.
This chapter covers the full spectrum of COBOL error handling: from the DECLARATIVES section and file status codes through inline exception phrases, the COBOL 2002 RAISE/RESUME mechanism, IBM-specific condition handling, common abend codes, and defensive programming patterns that prevent errors from reaching production in the first place.
16.1 The DECLARATIVES Section
The DECLARATIVES section is a special area of the PROCEDURE DIVISION that contains error-handling procedures. These procedures are not called directly by your code; instead, they are triggered automatically by the runtime system when specific error conditions occur during file I/O operations.
Syntax and Structure
The DECLARATIVES section must appear at the very beginning of the PROCEDURE DIVISION, before any other sections or paragraphs:
PROCEDURE DIVISION.
DECLARATIVES.
INPUT-ERROR SECTION.
USE AFTER STANDARD ERROR PROCEDURE ON INPUT-FILE.
INPUT-ERROR-HANDLER.
DISPLAY 'I/O ERROR ON INPUT-FILE'
DISPLAY 'FILE STATUS: ' WS-INPUT-STATUS
SET WS-INPUT-ERROR TO TRUE
.
OUTPUT-ERROR SECTION.
USE AFTER STANDARD ERROR PROCEDURE ON OUTPUT-FILE.
OUTPUT-ERROR-HANDLER.
DISPLAY 'I/O ERROR ON OUTPUT-FILE'
DISPLAY 'FILE STATUS: ' WS-OUTPUT-STATUS
SET WS-OUTPUT-ERROR TO TRUE
.
END DECLARATIVES.
MAIN-PROCESSING SECTION.
0000-MAIN.
PERFORM 1000-INITIALIZE
PERFORM 2000-PROCESS
PERFORM 3000-TERMINATE
STOP RUN
.
Key Rules for DECLARATIVES
There are several important rules governing the DECLARATIVES section:
-
Position: DECLARATIVES must be the first thing after PROCEDURE DIVISION. No other code can precede it.
-
Section requirement: Each USE statement must be in its own section. The section header provides the name, and the USE statement specifies the condition that triggers it.
-
END DECLARATIVES: The section ends with the
END DECLARATIVES.statement. -
No direct PERFORM: You should not PERFORM a declarative section from your main logic. The runtime invokes it automatically.
-
Scope: When the declarative procedure finishes, control returns to the statement following the I/O statement that caused the error.
-
File status: The file status variable is set before the declarative procedure executes, so you can examine it within the handler.
The USE Statement Variations
The USE statement specifies when a declarative procedure should be invoked. There are several forms:
* Triggered by errors on a specific file
USE AFTER STANDARD ERROR PROCEDURE ON file-name
* Triggered by errors on any file opened for INPUT
USE AFTER STANDARD ERROR PROCEDURE ON INPUT
* Triggered by errors on any file opened for OUTPUT
USE AFTER STANDARD ERROR PROCEDURE ON OUTPUT
* Triggered by errors on any file opened for I-O
USE AFTER STANDARD ERROR PROCEDURE ON I-O
* Triggered by errors on any file opened for EXTEND
USE AFTER STANDARD ERROR PROCEDURE ON EXTEND
The keyword EXCEPTION can be used interchangeably with ERROR in the COBOL 2002 standard:
USE AFTER STANDARD EXCEPTION PROCEDURE ON INPUT-FILE
Priority Rules
When multiple declarative sections could apply to a single error (for example, a file-specific handler and an INPUT handler both existing when an input file encounters an error), the most specific handler takes precedence. A file-specific USE statement overrides a general INPUT/OUTPUT/I-O/EXTEND handler.
A Complete DECLARATIVES Example
IDENTIFICATION DIVISION.
PROGRAM-ID. DECLDEMO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CUSTOMER-FILE
ASSIGN TO CUSTFILE
ORGANIZATION IS INDEXED
ACCESS MODE IS RANDOM
RECORD KEY IS CUST-ID
FILE STATUS IS WS-CUST-STATUS.
SELECT REPORT-FILE
ASSIGN TO RPTFILE
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-RPT-STATUS.
DATA DIVISION.
FILE SECTION.
FD CUSTOMER-FILE.
01 CUSTOMER-RECORD.
05 CUST-ID PIC X(10).
05 CUST-NAME PIC X(30).
05 CUST-BALANCE PIC S9(7)V99 COMP-3.
FD REPORT-FILE.
01 REPORT-RECORD PIC X(132).
WORKING-STORAGE SECTION.
01 WS-CUST-STATUS PIC XX.
01 WS-RPT-STATUS PIC XX.
01 WS-ERROR-FLAGS.
05 WS-CUST-ERROR-FLAG PIC 9 VALUE 0.
88 WS-CUST-OK VALUE 0.
88 WS-CUST-ERROR VALUE 1.
05 WS-RPT-ERROR-FLAG PIC 9 VALUE 0.
88 WS-RPT-OK VALUE 0.
88 WS-RPT-ERROR VALUE 1.
01 WS-ERROR-MESSAGE PIC X(80).
PROCEDURE DIVISION.
DECLARATIVES.
CUST-FILE-ERROR SECTION.
USE AFTER STANDARD ERROR PROCEDURE
ON CUSTOMER-FILE.
CUST-FILE-ERROR-HANDLER.
STRING 'CUSTOMER FILE ERROR - STATUS: '
WS-CUST-STATUS
' DURING I/O OPERATION'
DELIMITED BY SIZE
INTO WS-ERROR-MESSAGE
END-STRING
DISPLAY WS-ERROR-MESSAGE
SET WS-CUST-ERROR TO TRUE
.
RPT-FILE-ERROR SECTION.
USE AFTER STANDARD ERROR PROCEDURE
ON REPORT-FILE.
RPT-FILE-ERROR-HANDLER.
STRING 'REPORT FILE ERROR - STATUS: '
WS-RPT-STATUS
DELIMITED BY SIZE
INTO WS-ERROR-MESSAGE
END-STRING
DISPLAY WS-ERROR-MESSAGE
SET WS-RPT-ERROR TO TRUE
.
END DECLARATIVES.
MAIN-SECTION SECTION.
0000-MAIN.
PERFORM 1000-OPEN-FILES
IF WS-CUST-OK AND WS-RPT-OK
PERFORM 2000-PROCESS-RECORDS
END-IF
PERFORM 3000-CLOSE-FILES
STOP RUN
.
16.2 File Status Codes: Complete Reference
File status codes are the primary mechanism for detecting and diagnosing I/O errors in COBOL. Every production COBOL program should define a FILE STATUS variable for every file it uses. After every I/O operation (OPEN, READ, WRITE, REWRITE, DELETE, START, CLOSE), the runtime places a two-character code in this variable that indicates the outcome of the operation.
Defining File Status
FILE-CONTROL.
SELECT MASTER-FILE
ASSIGN TO MSTFILE
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS MST-KEY
FILE STATUS IS WS-MST-STATUS.
WORKING-STORAGE SECTION.
01 WS-MST-STATUS PIC XX.
88 WS-MST-SUCCESS VALUE '00'.
88 WS-MST-EOF VALUE '10'.
88 WS-MST-DUPKEY VALUE '22'.
88 WS-MST-NOT-FOUND VALUE '23'.
Complete File Status Code Reference
The file status code consists of two characters. The first character indicates the general category (status key 1), and the second character provides specific information within that category (status key 2).
Status Key 1 = '0': Successful Completion
| Code | Meaning |
|---|---|
| 00 | Operation completed successfully. No error, no exceptional condition. |
| 02 | Operation successful, but a duplicate key was detected. For READ, the record read has a duplicate alternate key. For WRITE or REWRITE, the record was written but created a duplicate alternate key value. |
| 04 | Operation successful, but the length of the record read does not match the fixed-length record description. (Record length mismatch.) |
| 05 | Operation successful. The OPEN refers to an optional file that is not present. The file will be created if it is opened for output. |
| 07 | Operation successful. For CLOSE with NO REWIND, REEL/UNIT, or FOR REMOVAL, the file is not on a reel/unit medium. For OPEN, the file is not on a reel/unit medium and the OPEN mode does not conflict with the file position. |
Status Key 1 = '1': AT END Condition
| Code | Meaning |
|---|---|
| 10 | End of file reached. A sequential READ was attempted and no next logical record existed. This is the normal end-of-file condition. |
| 14 | A sequential READ was attempted on a relative file and the number of significant digits in the relative record number is larger than the size of the relative key data item. |
Status Key 1 = '2': INVALID KEY Condition
| Code | Meaning |
|---|---|
| 21 | Sequence error. A sequential WRITE attempted to write a record with a key value that is not in ascending order, or the key was changed between a successful READ and the subsequent REWRITE. |
| 22 | Duplicate key. An attempt was made to WRITE or REWRITE a record that would create a duplicate value in a key field that does not allow duplicates. |
| 23 | Record not found. A READ, START, or DELETE attempted to access a record identified by a key, and that key value does not exist in the file. |
| 24 | Boundary violation. A WRITE went beyond the externally defined boundaries of the file. For an indexed file, this may mean the file is full. For a relative file, an attempt to WRITE beyond the limits of the file. |
Status Key 1 = '3': Permanent Error
| Code | Meaning |
|---|---|
| 30 | Permanent I/O error. A hardware-level failure occurred that cannot be further classified. The operating system was unable to complete the I/O operation. |
| 34 | Boundary violation. A sequential WRITE was attempted and the file could not be extended because the disk was full or the maximum file size was reached. |
| 35 | An OPEN was attempted on a non-optional file that does not exist. The file is required but not present. |
| 37 | An OPEN was attempted on a file that does not support the specified open mode. For example, attempting to OPEN OUTPUT on a file that only supports input. |
| 38 | An OPEN was attempted on a file previously closed WITH LOCK. |
| 39 | A conflict was detected between the file attributes specified in the program and the actual file attributes. For example, the RECORD CONTAINS clause specifies a different length than the actual file records. |
Status Key 1 = '4': Logic Error
| Code | Meaning |
|---|---|
| 41 | An OPEN was attempted on a file that is already open. |
| 42 | A CLOSE was attempted on a file that is not open. |
| 43 | For a sequential access file, the last I/O operation was not a successful READ before a REWRITE or DELETE was attempted. |
| 44 | A boundary violation occurred. A WRITE or REWRITE attempted to store a record that is larger than the maximum or smaller than the minimum record size allowed by the file description. |
| 46 | A sequential READ was attempted on a file opened for input or I-O, but no valid next record had been established because the previous READ was unsuccessful. |
| 47 | A READ or START was attempted on a file not opened for INPUT or I-O. |
| 48 | A WRITE was attempted on a file not opened for OUTPUT, I-O, or EXTEND. |
| 49 | A DELETE or REWRITE was attempted on a file not opened for I-O. |
Status Key 1 = '9': Implementor-Defined
| Code | Meaning |
|---|---|
| 90 | Implementor-defined. On IBM z/OS, typically indicates a VSAM-specific error. |
| 91 | Implementor-defined. VSAM password failure (z/OS). |
| 92 | Implementor-defined. Logic error (IBM). |
| 93 | Implementor-defined. VSAM resource not available. |
| 96 | Implementor-defined. Missing DD statement (z/OS). |
| 97 | Implementor-defined. File integrity verification failed. |
Checking File Status in Practice
The most robust approach to file status checking uses a centralized routine:
WORKING-STORAGE SECTION.
01 WS-FILE-STATUS PIC XX.
01 WS-FILE-NAME PIC X(30).
01 WS-IO-OPERATION PIC X(10).
01 WS-EXPECTED-STATUS PIC XX.
01 WS-FILE-ERROR-FLAG PIC 9 VALUE 0.
88 WS-FILE-OK VALUE 0.
88 WS-FILE-ERROR VALUE 1.
PROCEDURE DIVISION.
9000-CHECK-FILE-STATUS.
IF WS-FILE-STATUS NOT = WS-EXPECTED-STATUS
DISPLAY '*** FILE I/O ERROR ***'
DISPLAY 'FILE NAME: ' WS-FILE-NAME
DISPLAY 'OPERATION: ' WS-IO-OPERATION
DISPLAY 'STATUS: ' WS-FILE-STATUS
DISPLAY 'EXPECTED: ' WS-EXPECTED-STATUS
SET WS-FILE-ERROR TO TRUE
END-IF
.
1100-OPEN-INPUT-FILE.
OPEN INPUT CUSTOMER-FILE
MOVE WS-CUST-STATUS TO WS-FILE-STATUS
MOVE 'CUSTOMER-FILE' TO WS-FILE-NAME
MOVE 'OPEN INPUT' TO WS-IO-OPERATION
MOVE '00' TO WS-EXPECTED-STATUS
PERFORM 9000-CHECK-FILE-STATUS
.
2100-READ-CUSTOMER.
READ CUSTOMER-FILE
INTO WS-CUSTOMER-RECORD
END-READ
MOVE WS-CUST-STATUS TO WS-FILE-STATUS
MOVE 'CUSTOMER-FILE' TO WS-FILE-NAME
MOVE 'READ' TO WS-IO-OPERATION
EVALUATE TRUE
WHEN WS-CUST-STATUS = '00'
CONTINUE
WHEN WS-CUST-STATUS = '10'
SET WS-END-OF-FILE TO TRUE
WHEN OTHER
PERFORM 9000-CHECK-FILE-STATUS
END-EVALUATE
.
16.3 Inline Exception Handling: ON SIZE ERROR
The ON SIZE ERROR phrase is used with arithmetic statements (ADD, SUBTRACT, MULTIPLY, DIVIDE, COMPUTE) to detect situations where the result of a calculation is too large to fit in the receiving field, or when a division by zero occurs.
Without ON SIZE ERROR
Without ON SIZE ERROR, an arithmetic overflow is silently truncated. The result is wrong, and the program continues as if nothing happened:
01 WS-AMOUNT PIC 9(3) VALUE 999.
01 WS-INCREMENT PIC 9(3) VALUE 5.
ADD WS-INCREMENT TO WS-AMOUNT
* WS-AMOUNT now contains 004 (1004 truncated to 3 digits)
* No error is raised -- the program continues with bad data
This silent truncation is one of the most dangerous behaviors in COBOL. In financial applications, it can cause millions of dollars in discrepancies that are extremely difficult to trace.
With ON SIZE ERROR
ADD WS-INCREMENT TO WS-AMOUNT
ON SIZE ERROR
DISPLAY 'ARITHMETIC OVERFLOW IN ADD'
DISPLAY 'AMOUNT: ' WS-AMOUNT
DISPLAY 'INCREMENT: ' WS-INCREMENT
MOVE 99 TO WS-RETURN-CODE
NOT ON SIZE ERROR
ADD 1 TO WS-RECORDS-PROCESSED
END-ADD
When ON SIZE ERROR is specified and an overflow occurs, the receiving field is not modified (it retains its previous value) and the imperative statements following ON SIZE ERROR are executed. When no overflow occurs, the NOT ON SIZE ERROR statements execute.
Division by Zero
The ON SIZE ERROR phrase is the only safe way to handle division by zero in COBOL:
DIVIDE WS-TOTAL-AMOUNT BY WS-NUM-TRANSACTIONS
GIVING WS-AVERAGE-AMOUNT
REMAINDER WS-REMAINDER
ON SIZE ERROR
DISPLAY 'DIVISION BY ZERO OR OVERFLOW'
MOVE ZEROS TO WS-AVERAGE-AMOUNT
NOT ON SIZE ERROR
CONTINUE
END-DIVIDE
COMPUTE with ON SIZE ERROR
The COMPUTE statement is particularly important to protect because it can involve complex expressions where overflow is harder to predict:
COMPUTE WS-COMPOUND-INTEREST =
WS-PRINCIPAL *
((1 + WS-RATE / 100) ** WS-YEARS - 1)
ON SIZE ERROR
DISPLAY 'INTEREST CALCULATION OVERFLOW'
DISPLAY 'PRINCIPAL: ' WS-PRINCIPAL
DISPLAY 'RATE: ' WS-RATE
DISPLAY 'YEARS: ' WS-YEARS
MOVE HIGH-VALUES TO WS-COMPOUND-INTEREST
NOT ON SIZE ERROR
CONTINUE
END-COMPUTE
16.4 ON OVERFLOW for String Operations
The ON OVERFLOW phrase applies to the STRING and UNSTRING statements. It triggers when the destination field is too small to hold the concatenated result (STRING) or when there are more source segments than receiving fields (UNSTRING).
STRING with ON OVERFLOW
01 WS-FULL-NAME PIC X(40).
01 WS-POINTER PIC 99 VALUE 1.
STRING
WS-FIRST-NAME DELIMITED BY SPACES
' ' DELIMITED BY SIZE
WS-MIDDLE-INIT DELIMITED BY SPACES
'. ' DELIMITED BY SIZE
WS-LAST-NAME DELIMITED BY SPACES
INTO WS-FULL-NAME
WITH POINTER WS-POINTER
ON OVERFLOW
DISPLAY 'NAME TRUNCATED: EXCEEDS 40 CHARS'
MOVE 'Y' TO WS-NAME-TRUNCATED
NOT ON OVERFLOW
MOVE 'N' TO WS-NAME-TRUNCATED
END-STRING
UNSTRING with ON OVERFLOW
01 WS-INPUT-LINE PIC X(80).
01 WS-FIELD-1 PIC X(20).
01 WS-FIELD-2 PIC X(20).
01 WS-FIELD-3 PIC X(20).
01 WS-FIELD-COUNT PIC 99.
UNSTRING WS-INPUT-LINE
DELIMITED BY ',' OR SPACES
INTO WS-FIELD-1
WS-FIELD-2
WS-FIELD-3
TALLYING IN WS-FIELD-COUNT
ON OVERFLOW
DISPLAY 'MORE FIELDS THAN EXPECTED: '
WS-FIELD-COUNT
NOT ON OVERFLOW
CONTINUE
END-UNSTRING
16.5 INVALID KEY for File Operations
The INVALID KEY phrase applies to random-access file operations on indexed and relative files: READ (with KEY IS), WRITE, REWRITE, DELETE, and START. It triggers when the operation fails because the specified key value does not exist, already exists (for a unique key write), or is out of sequence.
READ with INVALID KEY
MOVE WS-SEARCH-KEY TO CUST-KEY
READ CUSTOMER-FILE
INTO WS-CUSTOMER-RECORD
KEY IS CUST-KEY
INVALID KEY
DISPLAY 'CUSTOMER NOT FOUND: ' WS-SEARCH-KEY
SET WS-CUSTOMER-NOT-FOUND TO TRUE
NOT INVALID KEY
SET WS-CUSTOMER-FOUND TO TRUE
ADD 1 TO WS-RECORDS-READ
END-READ
WRITE with INVALID KEY
WRITE CUSTOMER-RECORD
FROM WS-NEW-CUSTOMER
INVALID KEY
EVALUATE WS-CUST-STATUS
WHEN '22'
DISPLAY 'DUPLICATE KEY: '
WS-NEW-CUSTOMER-KEY
WHEN '24'
DISPLAY 'FILE IS FULL'
WHEN OTHER
DISPLAY 'WRITE ERROR, STATUS: '
WS-CUST-STATUS
END-EVALUATE
NOT INVALID KEY
ADD 1 TO WS-RECORDS-WRITTEN
END-WRITE
DELETE with INVALID KEY
MOVE WS-DELETE-KEY TO CUST-KEY
DELETE CUSTOMER-FILE RECORD
INVALID KEY
DISPLAY 'CANNOT DELETE - NOT FOUND: '
WS-DELETE-KEY
ADD 1 TO WS-DELETE-ERRORS
NOT INVALID KEY
ADD 1 TO WS-RECORDS-DELETED
END-DELETE
START with INVALID KEY
MOVE WS-START-KEY TO CUST-KEY
START CUSTOMER-FILE
KEY IS >= CUST-KEY
INVALID KEY
DISPLAY 'NO RECORDS >= ' WS-START-KEY
SET WS-NO-RECORDS TO TRUE
NOT INVALID KEY
SET WS-RECORDS-EXIST TO TRUE
END-START
16.6 AT END for Sequential Reads
The AT END phrase is used with the sequential READ statement to detect the end-of-file condition (file status '10'). This is the most commonly used inline exception phrase in COBOL, appearing in virtually every program that reads a sequential file.
Basic AT END Pattern
01 WS-EOF-FLAG PIC 9 VALUE 0.
88 WS-NOT-EOF VALUE 0.
88 WS-EOF VALUE 1.
2000-PROCESS-FILE.
PERFORM 2100-READ-INPUT
PERFORM UNTIL WS-EOF
PERFORM 2200-PROCESS-RECORD
PERFORM 2100-READ-INPUT
END-PERFORM
.
2100-READ-INPUT.
READ INPUT-FILE
INTO WS-INPUT-RECORD
AT END
SET WS-EOF TO TRUE
NOT AT END
ADD 1 TO WS-RECORDS-READ
END-READ
.
RETURN with AT END
When using INPUT PROCEDURE or OUTPUT PROCEDURE with a SORT statement, the RETURN statement replaces READ, and it also supports AT END:
OUTPUT-PROCEDURE-SECTION SECTION.
PERFORM UNTIL WS-EOF
RETURN SORT-FILE
INTO WS-SORTED-RECORD
AT END
SET WS-EOF TO TRUE
NOT AT END
PERFORM WRITE-SORTED-RECORD
END-RETURN
END-PERFORM
.
16.7 COBOL 2002 RAISE and RESUME: Structured Exception Handling
The COBOL 2002 standard introduced a structured exception handling mechanism modeled on the try/catch paradigm found in modern programming languages. This feature uses three new statements: RAISE, RESUME, and an extended form of the DECLARATIVES section using USE AFTER EXCEPTION.
Note on Availability
The RAISE/RESUME mechanism is part of the ISO 2002 COBOL standard and is supported by GnuCOBOL (version 3.0 and later with appropriate configuration) and Micro Focus COBOL. IBM Enterprise COBOL as of version 6.4 does not support RAISE/RESUME; IBM instead relies on Language Environment condition handling, which is covered in Section 16.8. If you are working on IBM mainframes, you should be aware of the COBOL 2002 mechanism for portability and future reference, but you will use LE condition handling in practice.
Defining Exception Names
Exception names are defined in the SPECIAL-NAMES paragraph of the ENVIRONMENT DIVISION:
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
REPOSITORY.
FUNCTION ALL INTRINSIC.
SPECIAL-NAMES.
EC-SIZE
EC-SIZE-ZERO-DIVIDE
EC-DATA
EC-DATA-INCOMPATIBLE
EC-FLOW
EC-FLOW-GLOBAL-GOBACK
.
The COBOL 2002 standard defines a hierarchy of exception classes. The top-level classes include EC-SIZE (arithmetic errors), EC-DATA (data conversion errors), EC-FLOW (control flow errors), EC-I-O (input/output errors), EC-RANGE (subscript and reference modification range errors), and others.
The RAISE Statement
The RAISE statement explicitly signals an exception condition:
* Raise a predefined exception
RAISE EC-SIZE-ZERO-DIVIDE
* Raise a user-defined exception object
RAISE EXCEPTION WS-MY-EXCEPTION
Exception Handling with USE AFTER EXCEPTION
Declarative procedures can catch raised exceptions:
PROCEDURE DIVISION.
DECLARATIVES.
SIZE-ERROR SECTION.
USE AFTER EXCEPTION CONDITION EC-SIZE.
SIZE-ERROR-HANDLER.
DISPLAY 'SIZE ERROR CAUGHT'
DISPLAY 'EXCEPTION: '
FUNCTION EXCEPTION-STATUS
RESUME AT NEXT STATEMENT
.
END DECLARATIVES.
MAIN-SECTION SECTION.
0000-MAIN.
COMPUTE WS-RESULT = WS-A / WS-B
* If WS-B is zero, control transfers to
* SIZE-ERROR-HANDLER, then RESUME AT NEXT
* STATEMENT brings control here:
DISPLAY 'AFTER COMPUTE'
STOP RUN
.
The RESUME Statement
The RESUME statement is used within a declarative exception handler to specify where execution should continue after the exception has been handled:
* Continue with the next statement after the one that
* raised the exception
RESUME AT NEXT STATEMENT
* Transfer control to a specific paragraph or section
RESUME AT 9000-ERROR-EXIT
TURN Directive for Exception Checking
The TURN directive controls which exception conditions are actively checked:
>>TURN EC-SIZE CHECKING ON
>>TURN EC-DATA CHECKING ON
>>TURN EC-RANGE CHECKING ON
* These exceptions are now actively monitored
* Performance cost: runtime checks are inserted
>>TURN EC-SIZE CHECKING OFF
* Size checks are no longer performed
Practical Example with RAISE/RESUME
IDENTIFICATION DIVISION.
PROGRAM-ID. RAISEDEM.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUMERATOR PIC 9(5) VALUE 100.
01 WS-DENOMINATOR PIC 9(5) VALUE 0.
01 WS-RESULT PIC 9(5)V99.
01 WS-ERROR-COUNT PIC 9(3) VALUE 0.
PROCEDURE DIVISION.
DECLARATIVES.
ARITH-ERROR SECTION.
USE AFTER EXCEPTION CONDITION EC-SIZE.
ARITH-ERROR-PARA.
ADD 1 TO WS-ERROR-COUNT
DISPLAY 'ARITHMETIC EXCEPTION HANDLED'
DISPLAY 'ERROR COUNT: ' WS-ERROR-COUNT
MOVE 0 TO WS-RESULT
RESUME AT NEXT STATEMENT
.
END DECLARATIVES.
MAIN-SECTION SECTION.
MAIN-PARA.
DIVIDE WS-NUMERATOR BY WS-DENOMINATOR
GIVING WS-RESULT
END-DIVIDE
DISPLAY 'RESULT: ' WS-RESULT
DISPLAY 'PROGRAM CONTINUES NORMALLY'
STOP RUN
.
16.8 IBM Language Environment Condition Handling
On IBM z/OS mainframes, COBOL programs run within the Language Environment (LE), a common runtime environment shared by COBOL, PL/I, C, and Assembler programs. LE provides a sophisticated condition handling model that intercepts errors at a level below the COBOL language, handling hardware interrupts (program checks), software-detected errors, and user-defined conditions.
The LE Condition Handling Model
LE classifies conditions by severity:
| Severity | Meaning | Default Action |
|---|---|---|
| 0 | Information | Continue |
| 1 | Warning | Continue |
| 2 | Error | Continue with default correction |
| 3 | Severe error | Terminate the enclave |
| 4 | Critical error | Terminate the enclave |
Condition Tokens
Every LE condition is identified by a 12-byte condition token stored in a feedback code structure. The condition token contains a condition ID, a facility ID (identifying the component that detected the condition), and severity information.
The CEECBLCK Copybook
IBM provides the CEECBLCK copybook that defines the LE condition handling data structures:
WORKING-STORAGE SECTION.
COPY CEECBLCK.
* The copybook defines:
* 01 FC. (Feedback Code)
* 05 Condition-ID.
* 10 Case-1-Condition-ID.
* 15 Severity PIC S9(4) COMP.
* 15 Msg-No PIC S9(4) COMP.
* 10 Case-2-Condition-ID
* REDEFINES Case-1-Condition-ID.
* 15 Class-Code PIC S9(4) COMP.
* 15 Cause-Code PIC S9(4) COMP.
* 05 Facility-ID PIC X(3).
* 05 I-S-Info PIC S9(9) COMP.
Using CEE3SRP to Set Resume Points
The CEE3SRP service establishes a resume point. If a condition occurs that would normally terminate the program, LE can instead resume execution at the resume point:
WORKING-STORAGE SECTION.
COPY CEECBLCK.
01 WS-RESUME-TOKEN PIC S9(9) COMP VALUE 0.
PROCEDURE DIVISION.
1000-MAIN.
CALL 'CEE3SRP'
USING WS-RESUME-TOKEN
FC
END-CALL
EVALUATE TRUE
WHEN WS-RESUME-TOKEN = 0
* Normal flow -- first time through
PERFORM 2000-RISKY-OPERATION
WHEN WS-RESUME-TOKEN = 1
* We got here via resume after an error
DISPLAY 'RECOVERED FROM ERROR'
PERFORM 9000-ERROR-RECOVERY
END-EVALUATE
.
CEECBLCK Return Code Checking
A common pattern uses LE callable services and checks the feedback code:
WORKING-STORAGE SECTION.
COPY CEECBLCK.
01 WS-DATE-INT PIC S9(9) COMP.
01 WS-INPUT-DATE PIC X(8) VALUE '20250230'.
01 WS-DATE-PICTURE PIC X(8) VALUE 'YYYYMMDD'.
PROCEDURE DIVISION.
1000-VALIDATE-DATE.
CALL 'CEEDAYS'
USING WS-INPUT-DATE
WS-DATE-PICTURE
WS-DATE-INT
FC
END-CALL
IF CEE000 OF FC
DISPLAY 'DATE IS VALID'
DISPLAY 'LILLIAN DAY: ' WS-DATE-INT
ELSE
DISPLAY 'INVALID DATE: ' WS-INPUT-DATE
DISPLAY 'SEVERITY: ' Severity OF FC
DISPLAY 'MSG-NO: ' Msg-No OF FC
END-IF
.
16.9 Return Codes and Program Communication
Return codes are the standard mechanism for communicating success or failure between COBOL programs and between COBOL programs and the operating system.
The RETURN-CODE Special Register
IBM Enterprise COBOL provides the RETURN-CODE special register, a fullword binary (PIC S9(4) COMP) field that is automatically available without declaration:
PROCEDURE DIVISION.
0000-MAIN.
PERFORM 1000-PROCESS
IF WS-ERROR-OCCURRED
MOVE 16 TO RETURN-CODE
ELSE
MOVE 0 TO RETURN-CODE
END-IF
STOP RUN
.
Standard Return Code Conventions
On z/OS mainframes, return codes follow a well-established convention:
| Return Code | Meaning |
|---|---|
| 0 | Successful completion |
| 4 | Warning -- processing completed but with minor issues |
| 8 | Error -- some processing could not be completed |
| 12 | Severe error -- significant processing failure |
| 16 | Terminal error -- program cannot continue |
| 20 | Catastrophic error -- system-level failure |
Checking Return Codes from Called Programs
01 WS-CALLED-RC PIC S9(4) COMP.
2000-CALL-SUBPROGRAM.
CALL 'VALIDATECUST'
USING WS-CUSTOMER-DATA
END-CALL
MOVE RETURN-CODE TO WS-CALLED-RC
EVALUATE WS-CALLED-RC
WHEN 0
PERFORM 2100-PROCESS-VALID-CUST
WHEN 4
DISPLAY 'WARNING FROM VALIDATION'
PERFORM 2100-PROCESS-VALID-CUST
WHEN 8
DISPLAY 'VALIDATION ERRORS FOUND'
PERFORM 2900-LOG-ERRORS
WHEN OTHER
DISPLAY 'SEVERE VALIDATION FAILURE, RC='
WS-CALLED-RC
PERFORM 9000-ABORT
END-EVALUATE
.
Setting Return Codes in Subprograms
IDENTIFICATION DIVISION.
PROGRAM-ID. VALIDATECUST.
DATA DIVISION.
LINKAGE SECTION.
01 LS-CUSTOMER-DATA.
05 LS-CUST-ID PIC X(10).
05 LS-CUST-NAME PIC X(30).
05 LS-CUST-BAL PIC S9(7)V99 COMP-3.
PROCEDURE DIVISION USING LS-CUSTOMER-DATA.
0000-VALIDATE.
MOVE 0 TO RETURN-CODE
IF LS-CUST-ID = SPACES
DISPLAY 'CUSTOMER ID IS BLANK'
MOVE 8 TO RETURN-CODE
END-IF
IF LS-CUST-NAME = SPACES
DISPLAY 'CUSTOMER NAME IS BLANK'
MOVE 8 TO RETURN-CODE
END-IF
IF LS-CUST-BAL < 0
DISPLAY 'WARNING: NEGATIVE BALANCE'
IF RETURN-CODE < 4
MOVE 4 TO RETURN-CODE
END-IF
END-IF
GOBACK
.
16.10 Common Abend Codes
An abend (abnormal end) occurs when a program terminates unexpectedly due to an unrecoverable error. On z/OS, abends are classified as system abends (S-type, issued by the operating system or subsystem) and user abends (U-type, issued by the program or runtime). Understanding common abend codes is essential for debugging production failures.
S0C7: Data Exception
The S0C7 is the most common COBOL abend. It occurs when a packed decimal (COMP-3) or zoned decimal field contains invalid data -- characters that are not valid digits in the expected format.
Common causes:
- An uninitialized WORKING-STORAGE variable used in arithmetic
- A file record containing corrupt data
- A MOVE of alphanumeric data into a numeric field without validation
- A REDEFINES that overlays a numeric field with incompatible data
- Reading past the end of a file without checking file status
Example that causes S0C7:
01 WS-AMOUNT PIC S9(5)V99 COMP-3.
01 WS-INPUT PIC X(10) VALUE 'ABC'.
* This will abend S0C7 when WS-AMOUNT is used in arithmetic:
MOVE WS-INPUT TO WS-AMOUNT
ADD WS-AMOUNT TO WS-TOTAL
Prevention:
01 WS-AMOUNT PIC S9(5)V99 COMP-3.
01 WS-INPUT PIC X(10).
IF WS-INPUT IS NUMERIC
MOVE WS-INPUT TO WS-AMOUNT
ADD WS-AMOUNT TO WS-TOTAL
ELSE
DISPLAY 'INVALID NUMERIC DATA: ' WS-INPUT
ADD 1 TO WS-ERROR-COUNT
END-IF
S0C4: Protection Exception
The S0C4 occurs when a program attempts to access memory that it does not own or that is not allocated. This is the COBOL equivalent of a segmentation fault.
Common causes:
- Subscript or index out of range (table overflow)
- Invalid address in a pointer or LINKAGE SECTION reference
- Called program not properly linked or not found (in some scenarios)
- CALL with a mismatched USING parameter list
- Reference modification with out-of-range offset or length
- Using a LINKAGE SECTION item when no data was passed
Example that causes S0C4:
01 WS-TABLE.
05 WS-ELEMENT PIC X(10) OCCURS 100 TIMES.
01 WS-INDEX PIC 9(4).
* If WS-INDEX = 101 or greater, S0C4:
MOVE 'DATA' TO WS-ELEMENT(WS-INDEX)
Prevention:
IF WS-INDEX > 0 AND WS-INDEX <= 100
MOVE 'DATA' TO WS-ELEMENT(WS-INDEX)
ELSE
DISPLAY 'INDEX OUT OF RANGE: ' WS-INDEX
ADD 1 TO WS-ERROR-COUNT
END-IF
S0C1: Operation Exception
The S0C1 occurs when the CPU encounters an invalid instruction. In COBOL, this typically means control has jumped to an area of memory that does not contain valid instructions.
Common causes:
- A CALL to a program name that resolves to an invalid address
- A corrupted program load module
- Falling through the end of a program without a STOP RUN or GOBACK
- An unresolved external reference at link-edit time
Prevention:
* Always use ON EXCEPTION with dynamic calls
CALL WS-PROGRAM-NAME
USING WS-PARAMETERS
ON EXCEPTION
DISPLAY 'PROGRAM NOT FOUND: '
WS-PROGRAM-NAME
MOVE 16 TO RETURN-CODE
END-CALL
* Always end programs with GOBACK or STOP RUN
0000-MAIN.
PERFORM 1000-PROCESS
GOBACK
.
S0CB: Division by Zero
The S0CB occurs when a fixed-point division by zero is attempted. While ON SIZE ERROR can prevent this for COBOL arithmetic statements, raw COMP arithmetic or arithmetic in called routines may still produce this abend.
Prevention:
IF WS-DIVISOR NOT = ZERO
DIVIDE WS-DIVIDEND BY WS-DIVISOR
GIVING WS-QUOTIENT
END-DIVIDE
ELSE
DISPLAY 'DIVISION BY ZERO AVOIDED'
MOVE ZEROS TO WS-QUOTIENT
END-IF
S322: Time Limit Exceeded
The S322 abend occurs when a job step exceeds its CPU time limit as specified by the TIME parameter on the JOB or EXEC JCL statement.
Common causes:
- An infinite loop in the program
- Processing a much larger file than expected
- A PERFORM UNTIL with a condition that is never satisfied
- Inefficient I/O patterns (reading an entire VSAM file randomly when sequential would suffice)
Prevention:
01 WS-LOOP-COUNTER PIC 9(9) COMP VALUE 0.
01 WS-MAX-ITERATIONS PIC 9(9) COMP VALUE 10000000.
2000-PROCESS-LOOP.
PERFORM UNTIL WS-DONE OR
WS-LOOP-COUNTER >= WS-MAX-ITERATIONS
ADD 1 TO WS-LOOP-COUNTER
PERFORM 2100-PROCESS-RECORD
PERFORM 2200-READ-NEXT
END-PERFORM
IF WS-LOOP-COUNTER >= WS-MAX-ITERATIONS
DISPLAY 'SAFETY LIMIT REACHED: POSSIBLE LOOP'
MOVE 16 TO RETURN-CODE
END-IF
.
S806: Module Not Found
The S806 abend occurs when a dynamically called program (CALL identifier) cannot be found in the load library concatenation.
Prevention:
CALL WS-PROGRAM-NAME
USING WS-PARAMETERS
ON EXCEPTION
DISPLAY 'S806 PREVENTED - MODULE NOT FOUND: '
WS-PROGRAM-NAME
MOVE 16 TO RETURN-CODE
NOT ON EXCEPTION
MOVE RETURN-CODE TO WS-SUB-RC
END-CALL
16.11 Error Logging Patterns
Production COBOL programs need comprehensive error logging to support problem diagnosis. Simply displaying an error message is not sufficient; production error logs need structured information that operations and support staff can use to identify, classify, and resolve problems quickly.
Structured Error Log Record
01 WS-ERROR-LOG-RECORD.
05 EL-TIMESTAMP.
10 EL-DATE PIC X(10).
10 FILLER PIC X VALUE ' '.
10 EL-TIME PIC X(08).
05 FILLER PIC X VALUE ' '.
05 EL-PROGRAM-ID PIC X(08).
05 FILLER PIC X VALUE ' '.
05 EL-SEVERITY PIC X(01).
88 EL-INFO VALUE 'I'.
88 EL-WARNING VALUE 'W'.
88 EL-ERROR VALUE 'E'.
88 EL-SEVERE VALUE 'S'.
05 FILLER PIC X VALUE ' '.
05 EL-ERROR-CODE PIC X(08).
05 FILLER PIC X VALUE ' '.
05 EL-PARAGRAPH PIC X(30).
05 FILLER PIC X VALUE ' '.
05 EL-MESSAGE PIC X(80).
05 FILLER PIC X VALUE ' '.
05 EL-DATA-1 PIC X(30).
05 FILLER PIC X VALUE ' '.
05 EL-DATA-2 PIC X(30).
Error Logging Routine
9100-LOG-ERROR.
MOVE FUNCTION CURRENT-DATE(1:4) TO EL-DATE(1:4)
MOVE '-' TO EL-DATE(5:1)
MOVE FUNCTION CURRENT-DATE(5:2) TO EL-DATE(6:2)
MOVE '-' TO EL-DATE(8:1)
MOVE FUNCTION CURRENT-DATE(7:2) TO EL-DATE(9:2)
MOVE FUNCTION CURRENT-DATE(9:2) TO EL-TIME(1:2)
MOVE ':' TO EL-TIME(3:1)
MOVE FUNCTION CURRENT-DATE(11:2) TO EL-TIME(4:2)
MOVE ':' TO EL-TIME(6:1)
MOVE FUNCTION CURRENT-DATE(13:2) TO EL-TIME(7:2)
MOVE 'CUSTPROC' TO EL-PROGRAM-ID
WRITE ERROR-LOG-RECORD
FROM WS-ERROR-LOG-RECORD
END-WRITE
ADD 1 TO WS-ERROR-COUNT
INITIALIZE WS-ERROR-LOG-RECORD
.
9200-LOG-FILE-ERROR.
SET EL-ERROR TO TRUE
MOVE WS-FILE-STATUS TO EL-ERROR-CODE
MOVE WS-CURRENT-PARA TO EL-PARAGRAPH
MOVE WS-FILE-ERROR-MSG TO EL-MESSAGE
MOVE WS-FILE-NAME TO EL-DATA-1
MOVE WS-IO-OPERATION TO EL-DATA-2
PERFORM 9100-LOG-ERROR
.
Error Summary Report
At the end of processing, a summary of all errors should be produced:
3000-PRODUCE-SUMMARY.
DISPLAY '========================================='
DISPLAY 'PROCESSING SUMMARY'
DISPLAY '========================================='
DISPLAY 'RECORDS READ: ' WS-RECORDS-READ
DISPLAY 'RECORDS PROCESSED: ' WS-RECORDS-PROCESSED
DISPLAY 'RECORDS WRITTEN: ' WS-RECORDS-WRITTEN
DISPLAY 'RECORDS IN ERROR: ' WS-ERROR-COUNT
DISPLAY '========================================='
IF WS-ERROR-COUNT > 0
DISPLAY '*** ERRORS OCCURRED - SEE ERROR LOG ***'
MOVE 8 TO RETURN-CODE
ELSE
DISPLAY 'PROCESSING COMPLETED SUCCESSFULLY'
MOVE 0 TO RETURN-CODE
END-IF
.
16.12 Defensive Programming Techniques
Defensive programming means writing code that anticipates and handles unexpected conditions before they become abends. In COBOL, where a single production failure can delay payroll processing or corrupt financial records, defensive programming is not optional -- it is a professional obligation.
Validate All Input Data
Never assume that data arriving from an external source (file, database, screen, or parameter) is valid:
3000-VALIDATE-INPUT-RECORD.
SET WS-RECORD-VALID TO TRUE
* Check required fields are not blank
IF IR-CUSTOMER-ID = SPACES
MOVE 'CUSTOMER ID IS BLANK'
TO WS-VALIDATION-MSG
PERFORM 3900-RECORD-ERROR
END-IF
* Check numeric fields contain valid numbers
IF IR-AMOUNT NOT NUMERIC
MOVE 'AMOUNT IS NOT NUMERIC'
TO WS-VALIDATION-MSG
PERFORM 3900-RECORD-ERROR
END-IF
* Check range validity
IF IR-AMOUNT IS NUMERIC
IF IR-AMOUNT > 999999.99
MOVE 'AMOUNT EXCEEDS MAXIMUM'
TO WS-VALIDATION-MSG
PERFORM 3900-RECORD-ERROR
END-IF
END-IF
* Check date validity
IF IR-TRANS-DATE NOT NUMERIC
MOVE 'TRANSACTION DATE NOT NUMERIC'
TO WS-VALIDATION-MSG
PERFORM 3900-RECORD-ERROR
ELSE
PERFORM 3100-VALIDATE-DATE
END-IF
* Check code fields against valid values
EVALUATE IR-TRANS-TYPE
WHEN 'C'
WHEN 'D'
WHEN 'T'
CONTINUE
WHEN OTHER
STRING 'INVALID TRANS TYPE: '
IR-TRANS-TYPE
DELIMITED BY SIZE
INTO WS-VALIDATION-MSG
END-STRING
PERFORM 3900-RECORD-ERROR
END-EVALUATE
.
Initialize All Variables
Uninitialized variables are a leading cause of S0C7 abends:
WORKING-STORAGE SECTION.
* Always initialize numeric fields
01 WS-TOTAL-AMOUNT PIC S9(7)V99 COMP-3 VALUE 0.
01 WS-RECORD-COUNT PIC 9(7) COMP-3 VALUE 0.
01 WS-ERROR-COUNT PIC 9(5) COMP-3 VALUE 0.
* Always initialize flags
01 WS-EOF-FLAG PIC 9 VALUE 0.
88 WS-NOT-EOF VALUE 0.
88 WS-EOF VALUE 1.
* Use INITIALIZE for group items
1000-INITIALIZE.
INITIALIZE WS-COUNTERS
INITIALIZE WS-ACCUMULATORS
INITIALIZE WS-FLAGS
.
Protect Array Boundaries
01 WS-STATE-TABLE.
05 WS-STATE-ENTRY OCCURS 50 TIMES
INDEXED BY WS-STATE-IDX.
10 WS-STATE-CODE PIC XX.
10 WS-STATE-NAME PIC X(20).
10 WS-STATE-TAX PIC V99.
01 WS-TABLE-SIZE PIC 99 VALUE 50.
4000-LOOKUP-STATE.
SET WS-STATE-IDX TO 1
SEARCH WS-STATE-ENTRY
AT END
DISPLAY 'STATE NOT FOUND: '
WS-SEARCH-STATE
SET WS-STATE-NOT-FOUND TO TRUE
WHEN WS-STATE-CODE(WS-STATE-IDX) =
WS-SEARCH-STATE
MOVE WS-STATE-NAME(WS-STATE-IDX)
TO WS-RESULT-NAME
MOVE WS-STATE-TAX(WS-STATE-IDX)
TO WS-RESULT-TAX
SET WS-STATE-FOUND TO TRUE
END-SEARCH
.
Always Check File Status After Every I/O
9000-CHECK-STATUS.
EVALUATE TRUE
WHEN WS-FILE-STATUS = '00'
CONTINUE
WHEN WS-FILE-STATUS = '10'
SET WS-EOF TO TRUE
WHEN WS-FILE-STATUS = '23'
SET WS-RECORD-NOT-FOUND TO TRUE
WHEN WS-FILE-STATUS = '02'
CONTINUE
WHEN WS-FILE-STATUS(1:1) = '9'
DISPLAY 'VSAM ERROR: ' WS-FILE-STATUS
DISPLAY 'ON FILE: ' WS-CURRENT-FILE
MOVE 16 TO RETURN-CODE
PERFORM 9999-ABORT
WHEN OTHER
DISPLAY 'UNEXPECTED STATUS: '
WS-FILE-STATUS
DISPLAY 'ON FILE: ' WS-CURRENT-FILE
MOVE 12 TO RETURN-CODE
PERFORM 9999-ABORT
END-EVALUATE
.
Guard Against Division by Zero
5000-CALCULATE-AVERAGE.
IF WS-COUNT > 0
DIVIDE WS-TOTAL BY WS-COUNT
GIVING WS-AVERAGE ROUNDED
ON SIZE ERROR
DISPLAY 'AVERAGE CALCULATION OVERFLOW'
MOVE 0 TO WS-AVERAGE
END-DIVIDE
ELSE
MOVE 0 TO WS-AVERAGE
END-IF
.
16.13 Production Error Handling Framework
A complete production error handling framework combines all the techniques discussed in this chapter into a cohesive structure. The following program demonstrates a complete framework that can be adapted for any batch COBOL application.
IDENTIFICATION DIVISION.
PROGRAM-ID. PRODFRAME.
*========================================================*
* PROGRAM: PRODFRAME *
* PURPOSE: Production Error Handling Framework *
* AUTHOR: Enterprise COBOL Team *
*========================================================*
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INPUT-FILE
ASSIGN TO INFILE
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-INPUT-STATUS.
SELECT OUTPUT-FILE
ASSIGN TO OUTFILE
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-OUTPUT-STATUS.
SELECT ERROR-FILE
ASSIGN TO ERRFILE
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-ERROR-STATUS.
SELECT ERROR-LOG
ASSIGN TO ERRLOG
ORGANIZATION IS SEQUENTIAL
FILE STATUS IS WS-LOG-STATUS.
DATA DIVISION.
FILE SECTION.
FD INPUT-FILE
RECORDING MODE IS F
RECORD CONTAINS 80 CHARACTERS.
01 INPUT-RECORD PIC X(80).
FD OUTPUT-FILE
RECORDING MODE IS F
RECORD CONTAINS 80 CHARACTERS.
01 OUTPUT-RECORD PIC X(80).
FD ERROR-FILE
RECORDING MODE IS F
RECORD CONTAINS 80 CHARACTERS.
01 ERROR-RECORD PIC X(80).
FD ERROR-LOG
RECORDING MODE IS F
RECORD CONTAINS 200 CHARACTERS.
01 LOG-RECORD PIC X(200).
WORKING-STORAGE SECTION.
01 WS-FILE-STATUSES.
05 WS-INPUT-STATUS PIC XX.
05 WS-OUTPUT-STATUS PIC XX.
05 WS-ERROR-STATUS PIC XX.
05 WS-LOG-STATUS PIC XX.
01 WS-CONTROL-FLAGS.
05 WS-EOF-FLAG PIC 9 VALUE 0.
88 WS-NOT-EOF VALUE 0.
88 WS-EOF VALUE 1.
05 WS-ABORT-FLAG PIC 9 VALUE 0.
88 WS-CONTINUE VALUE 0.
88 WS-ABORT VALUE 1.
01 WS-COUNTERS.
05 WS-READ-COUNT PIC 9(9) COMP VALUE 0.
05 WS-WRITE-COUNT PIC 9(9) COMP VALUE 0.
05 WS-ERROR-COUNT PIC 9(9) COMP VALUE 0.
05 WS-SKIP-COUNT PIC 9(9) COMP VALUE 0.
01 WS-ERROR-LIMITS.
05 WS-MAX-ERRORS PIC 9(5) COMP VALUE 100.
05 WS-MAX-CONSECUTIVE PIC 9(3) COMP VALUE 10.
05 WS-CONSEC-ERRORS PIC 9(3) COMP VALUE 0.
01 WS-ERROR-LOG-REC.
05 EL-TIMESTAMP PIC X(19).
05 FILLER PIC X VALUE '|'.
05 EL-SEVERITY PIC X(01).
05 FILLER PIC X VALUE '|'.
05 EL-COMPONENT PIC X(15).
05 FILLER PIC X VALUE '|'.
05 EL-ERROR-CODE PIC X(08).
05 FILLER PIC X VALUE '|'.
05 EL-MESSAGE PIC X(80).
05 FILLER PIC X VALUE '|'.
05 EL-RECORD-NUM PIC 9(09).
05 FILLER PIC X VALUE '|'.
05 EL-DATA-VALUE PIC X(60).
01 WS-INPUT-FIELDS.
05 WS-IN-CUST-ID PIC X(10).
05 WS-IN-CUST-NAME PIC X(30).
05 WS-IN-AMOUNT PIC X(10).
05 WS-IN-TRANS-TYPE PIC X.
05 FILLER PIC X(29).
01 WS-CURRENT-PARAGRAPH PIC X(30).
01 WS-CURRENT-FILE PIC X(20).
PROCEDURE DIVISION.
DECLARATIVES.
INPUT-FILE-ERROR SECTION.
USE AFTER STANDARD ERROR PROCEDURE ON INPUT-FILE.
INPUT-FILE-ERROR-PARA.
MOVE 'INPUT-FILE' TO WS-CURRENT-FILE
PERFORM 9100-LOG-IO-ERROR
.
OUTPUT-FILE-ERROR SECTION.
USE AFTER STANDARD ERROR PROCEDURE ON OUTPUT-FILE.
OUTPUT-FILE-ERROR-PARA.
MOVE 'OUTPUT-FILE' TO WS-CURRENT-FILE
PERFORM 9100-LOG-IO-ERROR
.
END DECLARATIVES.
MAIN-SECTION SECTION.
0000-MAIN.
PERFORM 1000-INITIALIZE
IF WS-CONTINUE
PERFORM 2000-PROCESS
UNTIL WS-EOF OR WS-ABORT
END-IF
PERFORM 3000-TERMINATE
STOP RUN
.
1000-INITIALIZE.
MOVE '1000-INITIALIZE' TO WS-CURRENT-PARAGRAPH
INITIALIZE WS-COUNTERS
OPEN INPUT INPUT-FILE
IF WS-INPUT-STATUS NOT = '00'
DISPLAY 'FATAL: CANNOT OPEN INPUT FILE, STATUS='
WS-INPUT-STATUS
SET WS-ABORT TO TRUE
MOVE 16 TO RETURN-CODE
END-IF
IF WS-CONTINUE
OPEN OUTPUT OUTPUT-FILE
IF WS-OUTPUT-STATUS NOT = '00'
DISPLAY 'FATAL: CANNOT OPEN OUTPUT, STATUS='
WS-OUTPUT-STATUS
SET WS-ABORT TO TRUE
MOVE 16 TO RETURN-CODE
END-IF
END-IF
IF WS-CONTINUE
OPEN OUTPUT ERROR-FILE
OPEN OUTPUT ERROR-LOG
PERFORM 2100-READ-INPUT
END-IF
.
2000-PROCESS.
MOVE '2000-PROCESS' TO WS-CURRENT-PARAGRAPH
MOVE INPUT-RECORD TO WS-INPUT-FIELDS
PERFORM 2200-VALIDATE-RECORD
IF WS-RECORD-VALID
PERFORM 2300-TRANSFORM-RECORD
PERFORM 2400-WRITE-OUTPUT
MOVE 0 TO WS-CONSEC-ERRORS
ELSE
PERFORM 2500-WRITE-ERROR
ADD 1 TO WS-CONSEC-ERRORS
PERFORM 2600-CHECK-ERROR-LIMITS
END-IF
PERFORM 2100-READ-INPUT
.
2100-READ-INPUT.
READ INPUT-FILE
AT END
SET WS-EOF TO TRUE
NOT AT END
ADD 1 TO WS-READ-COUNT
END-READ
IF WS-INPUT-STATUS NOT = '00'
AND WS-INPUT-STATUS NOT = '10'
DISPLAY 'READ ERROR, STATUS='
WS-INPUT-STATUS
SET WS-ABORT TO TRUE
END-IF
.
2200-VALIDATE-RECORD.
SET WS-RECORD-VALID TO TRUE
IF WS-IN-CUST-ID = SPACES
MOVE 'E' TO EL-SEVERITY
MOVE 'BLANK CUSTOMER ID' TO EL-MESSAGE
PERFORM 9200-LOG-DATA-ERROR
SET WS-RECORD-INVALID TO TRUE
END-IF
IF WS-IN-AMOUNT NOT NUMERIC
MOVE 'E' TO EL-SEVERITY
MOVE 'NON-NUMERIC AMOUNT' TO EL-MESSAGE
MOVE WS-IN-AMOUNT TO EL-DATA-VALUE
PERFORM 9200-LOG-DATA-ERROR
SET WS-RECORD-INVALID TO TRUE
END-IF
.
2300-TRANSFORM-RECORD.
* Business transformation logic here
CONTINUE
.
2400-WRITE-OUTPUT.
WRITE OUTPUT-RECORD FROM WS-INPUT-FIELDS
IF WS-OUTPUT-STATUS NOT = '00'
DISPLAY 'WRITE ERROR, STATUS='
WS-OUTPUT-STATUS
SET WS-ABORT TO TRUE
ELSE
ADD 1 TO WS-WRITE-COUNT
END-IF
.
2500-WRITE-ERROR.
WRITE ERROR-RECORD FROM INPUT-RECORD
ADD 1 TO WS-ERROR-COUNT
ADD 1 TO WS-SKIP-COUNT
.
2600-CHECK-ERROR-LIMITS.
IF WS-ERROR-COUNT >= WS-MAX-ERRORS
DISPLAY 'MAX ERROR LIMIT REACHED: '
WS-MAX-ERRORS
SET WS-ABORT TO TRUE
MOVE 16 TO RETURN-CODE
END-IF
IF WS-CONSEC-ERRORS >= WS-MAX-CONSECUTIVE
DISPLAY 'CONSECUTIVE ERROR LIMIT REACHED: '
WS-MAX-CONSECUTIVE
SET WS-ABORT TO TRUE
MOVE 16 TO RETURN-CODE
END-IF
.
3000-TERMINATE.
MOVE '3000-TERMINATE' TO WS-CURRENT-PARAGRAPH
DISPLAY '========================================='
DISPLAY 'PRODFRAME - PROCESSING SUMMARY'
DISPLAY '========================================='
DISPLAY 'RECORDS READ: ' WS-READ-COUNT
DISPLAY 'RECORDS WRITTEN: ' WS-WRITE-COUNT
DISPLAY 'RECORDS IN ERROR: ' WS-ERROR-COUNT
DISPLAY 'RECORDS SKIPPED: ' WS-SKIP-COUNT
DISPLAY '========================================='
IF WS-ABORT
DISPLAY '*** PROCESSING ABORTED ***'
END-IF
CLOSE INPUT-FILE
CLOSE OUTPUT-FILE
CLOSE ERROR-FILE
CLOSE ERROR-LOG
EVALUATE TRUE
WHEN WS-ERROR-COUNT = 0
MOVE 0 TO RETURN-CODE
WHEN WS-ERROR-COUNT <= 10
MOVE 4 TO RETURN-CODE
WHEN WS-ABORT
MOVE 16 TO RETURN-CODE
WHEN OTHER
MOVE 8 TO RETURN-CODE
END-EVALUATE
.
9100-LOG-IO-ERROR.
MOVE 'S' TO EL-SEVERITY
STRING 'I/O ERROR ON ' WS-CURRENT-FILE
' STATUS=' WS-INPUT-STATUS
DELIMITED BY SIZE
INTO EL-MESSAGE
END-STRING
PERFORM 9300-WRITE-LOG
.
9200-LOG-DATA-ERROR.
MOVE WS-READ-COUNT TO EL-RECORD-NUM
MOVE WS-CURRENT-PARAGRAPH TO EL-COMPONENT
PERFORM 9300-WRITE-LOG
.
9300-WRITE-LOG.
MOVE FUNCTION CURRENT-DATE(1:8) TO
EL-TIMESTAMP(1:8)
MOVE '-' TO EL-TIMESTAMP(5:1)
EL-TIMESTAMP(8:1)
MOVE ' ' TO EL-TIMESTAMP(11:1)
MOVE FUNCTION CURRENT-DATE(9:6) TO
EL-TIMESTAMP(12:6)
WRITE LOG-RECORD FROM WS-ERROR-LOG-REC
INITIALIZE WS-ERROR-LOG-REC
.
16.14 VSAM Extended Status Codes
On IBM z/OS, VSAM files return extended status information beyond the standard two-character file status code. When the first character of the file status is '9', the second character and additional VSAM-specific feedback codes provide diagnostic information that is essential for resolving VSAM file errors.
Accessing VSAM Return and Reason Codes
The VSAM return code and reason code are available through the file status variable and, on IBM Enterprise COBOL, through the VSAM return code areas. Some shops define an extended file status area:
01 WS-FILE-STATUS.
05 WS-STATUS-KEY-1 PIC X.
05 WS-STATUS-KEY-2 PIC X.
01 WS-VSAM-RETURN-CODE PIC S9(4) COMP.
01 WS-VSAM-COMPONENT-CODE PIC S9(4) COMP.
01 WS-VSAM-REASON-CODE PIC S9(4) COMP.
Common VSAM Error Scenarios
| File Status | VSAM RC | Description | Common Cause |
|---|---|---|---|
| 90 | 8 | Logic error | Sequence error on sequential PUT |
| 93 | 8/148 | Resource not available | Dataset is held by another job |
| 96 | -- | Missing DD | DD statement not in JCL |
| 97 | 8/96 | Implicit VERIFY failed | File was not closed properly |
| 35 | 8/40 | File not found | Dataset does not exist |
| 39 | 8/44 | Attribute mismatch | COBOL FD does not match file |
Diagnosing VSAM File Status 39
File status 39 (attribute mismatch) is one of the most frequently encountered VSAM errors. It means the file attributes defined in your COBOL program (record length, key position, key length, file organization) do not match the attributes of the physical VSAM dataset:
9100-DIAGNOSE-STATUS-39.
DISPLAY '*** FILE STATUS 39: ATTRIBUTE MISMATCH ***'
DISPLAY 'POSSIBLE CAUSES:'
DISPLAY '1. RECORD CONTAINS does not match'
DISPLAY ' VSAM record size (RECORDSIZE parameter)'
DISPLAY '2. RECORD KEY position/length does not'
DISPLAY ' match VSAM key definition (KEYS parameter)'
DISPLAY '3. ORGANIZATION does not match VSAM type'
DISPLAY ' (KSDS vs ESDS vs RRDS)'
DISPLAY '4. RECORDING MODE does not match'
DISPLAY ' (fixed vs variable length)'
DISPLAY 'CHECK: IDCAMS LISTCAT of the dataset'
DISPLAY ' against the COBOL FD and SELECT'
.
Centralized VSAM Error Diagnosis
9000-DIAGNOSE-FILE-ERROR.
EVALUATE WS-STATUS-KEY-1
WHEN '0'
DISPLAY 'SUCCESSFUL OR WARNING'
WHEN '1'
DISPLAY 'AT END CONDITION'
WHEN '2'
PERFORM 9010-INVALID-KEY-DIAGNOSIS
WHEN '3'
PERFORM 9020-PERMANENT-ERROR-DIAGNOSIS
WHEN '4'
PERFORM 9030-LOGIC-ERROR-DIAGNOSIS
WHEN '9'
PERFORM 9040-VSAM-ERROR-DIAGNOSIS
END-EVALUATE
.
9010-INVALID-KEY-DIAGNOSIS.
EVALUATE WS-FILE-STATUS
WHEN '21'
DISPLAY 'KEY SEQUENCE ERROR'
DISPLAY 'KEYS MUST BE IN ASCENDING ORDER'
DISPLAY 'CURRENT KEY: ' WS-CURRENT-KEY
DISPLAY 'PREVIOUS KEY: ' WS-PREVIOUS-KEY
WHEN '22'
DISPLAY 'DUPLICATE KEY'
DISPLAY 'ATTEMPTED KEY: ' WS-CURRENT-KEY
WHEN '23'
DISPLAY 'RECORD NOT FOUND'
DISPLAY 'SEARCHED KEY: ' WS-CURRENT-KEY
WHEN '24'
DISPLAY 'BOUNDARY VIOLATION'
DISPLAY 'FILE MAY BE FULL'
END-EVALUATE
.
9040-VSAM-ERROR-DIAGNOSIS.
DISPLAY 'VSAM-SPECIFIC ERROR'
DISPLAY 'FILE STATUS: ' WS-FILE-STATUS
DISPLAY 'VSAM RETURN CODE: '
WS-VSAM-RETURN-CODE
DISPLAY 'VSAM COMPONENT CODE: '
WS-VSAM-COMPONENT-CODE
DISPLAY 'VSAM REASON CODE: '
WS-VSAM-REASON-CODE
DISPLAY 'CONSULT DFSMS MACRO INSTRUCTIONS'
' FOR VSAM CODES'
.
16.15 Exception Handling in Called Programs
When a subprogram encounters an error, it must communicate that error to its caller. There are several patterns for doing this in COBOL.
Return Code Pattern
The simplest approach uses the RETURN-CODE special register:
* In the called program:
IDENTIFICATION DIVISION.
PROGRAM-ID. VALIDSUB.
DATA DIVISION.
LINKAGE SECTION.
01 LS-INPUT-DATA.
05 LS-FIELD-1 PIC X(10).
05 LS-FIELD-2 PIC 9(5).
PROCEDURE DIVISION USING LS-INPUT-DATA.
0000-VALIDATE.
MOVE 0 TO RETURN-CODE
IF LS-FIELD-1 = SPACES
MOVE 8 TO RETURN-CODE
GOBACK
END-IF
IF LS-FIELD-2 NOT NUMERIC
MOVE 8 TO RETURN-CODE
GOBACK
END-IF
GOBACK
.
Error Structure Pattern
For more detailed error reporting, pass an error structure through the LINKAGE SECTION:
* Error structure passed between caller and callee
01 WS-ERROR-BLOCK.
05 EB-RETURN-CODE PIC S9(4) COMP VALUE 0.
05 EB-ERROR-COUNT PIC S9(4) COMP VALUE 0.
05 EB-ERROR-TABLE.
10 EB-ERROR-ENTRY OCCURS 10 TIMES.
15 EB-ERR-FIELD PIC X(30).
15 EB-ERR-MSG PIC X(50).
* In the calling program:
INITIALIZE WS-ERROR-BLOCK
CALL 'VALIDSUB'
USING WS-INPUT-DATA
WS-ERROR-BLOCK
END-CALL
IF EB-RETURN-CODE NOT = 0
PERFORM VARYING WS-ERR-IDX FROM 1 BY 1
UNTIL WS-ERR-IDX > EB-ERROR-COUNT
DISPLAY EB-ERR-FIELD(WS-ERR-IDX) ': '
EB-ERR-MSG(WS-ERR-IDX)
END-PERFORM
END-IF
Exception Propagation
When a subprogram calls another subprogram and encounters an error, it should propagate the error to its caller rather than attempting to handle it independently. The general principle is: handle errors at the highest level that has enough context to take appropriate action.
* Mid-level subprogram that propagates errors upward
IDENTIFICATION DIVISION.
PROGRAM-ID. MIDLEVEL.
DATA DIVISION.
LINKAGE SECTION.
01 LS-REQUEST-DATA PIC X(100).
01 LS-RESULT-DATA PIC X(200).
01 LS-ERROR-BLOCK.
05 LS-RC PIC S9(4) COMP.
05 LS-ERROR-MSG PIC X(80).
PROCEDURE DIVISION USING LS-REQUEST-DATA
LS-RESULT-DATA
LS-ERROR-BLOCK.
0000-MAIN.
MOVE 0 TO LS-RC
CALL 'LOWLEVEL'
USING LS-REQUEST-DATA
LS-RESULT-DATA
LS-ERROR-BLOCK
END-CALL
* If the low-level program set an error, propagate it
IF LS-RC NOT = 0
GOBACK
END-IF
* Continue with mid-level processing
PERFORM 1000-PROCESS
GOBACK
.
16.16 Exception Handling Across Platforms
GnuCOBOL Exception Handling
GnuCOBOL supports the standard COBOL exception handling mechanisms (DECLARATIVES, file status codes, ON SIZE ERROR, AT END, INVALID KEY) and additionally supports portions of the COBOL 2002 RAISE/RESUME mechanism.
* GnuCOBOL supports the FUNCTION EXCEPTION-STATUS
* intrinsic function to retrieve the last exception
COMPUTE WS-RESULT = WS-A / WS-B
ON SIZE ERROR
DISPLAY 'EXCEPTION: '
FUNCTION EXCEPTION-STATUS
NOT ON SIZE ERROR
DISPLAY 'RESULT: ' WS-RESULT
END-COMPUTE
GnuCOBOL also supports runtime error handling through environment variables:
# Trap runtime errors and display details
export COB_SET_DEBUG=Y
# Set the runtime error procedure
# (GnuCOBOL-specific, not standard COBOL)
Micro Focus COBOL
Micro Focus COBOL supports all standard exception handling features and adds its own extensions, including the ability to trap runtime errors using the CBL_ERROR_PROC library routine:
CALL 'CBL_ERROR_PROC'
USING BY VALUE 0
BY REFERENCE ERROR-HANDLER-ADDRESS
END-CALL
16.17 Error Handling in Multi-Program Systems
Enterprise COBOL applications typically consist of many programs that call each other through CALL, CICS LINK, or DB2 stored procedures. Error handling in these systems requires a consistent, system-wide strategy.
Error Propagation Architecture
In a multi-program system, errors should propagate upward through the call chain until they reach a program that has enough context to take appropriate action. Lower-level utility programs should report errors but not make decisions about recovery. Higher-level controlling programs should decide whether to retry, skip, log, or terminate:
* Level 3: Low-level utility (reports errors)
IDENTIFICATION DIVISION.
PROGRAM-ID. DATEUTIL.
DATA DIVISION.
LINKAGE SECTION.
01 LS-INPUT-DATE PIC X(8).
01 LS-OUTPUT-DATE PIC X(10).
01 LS-RETURN-CODE PIC S9(4) COMP.
01 LS-ERROR-MSG PIC X(80).
PROCEDURE DIVISION USING LS-INPUT-DATE
LS-OUTPUT-DATE
LS-RETURN-CODE
LS-ERROR-MSG.
0000-CONVERT.
MOVE 0 TO LS-RETURN-CODE
MOVE SPACES TO LS-ERROR-MSG
IF LS-INPUT-DATE NOT NUMERIC
MOVE 8 TO LS-RETURN-CODE
MOVE 'DATE CONTAINS NON-NUMERIC DATA'
TO LS-ERROR-MSG
GOBACK
END-IF
* ... conversion logic ...
GOBACK
.
* Level 2: Business logic (handles or escalates errors)
IDENTIFICATION DIVISION.
PROGRAM-ID. TRANPROC.
WORKING-STORAGE SECTION.
01 WS-DATE-RC PIC S9(4) COMP.
01 WS-DATE-MSG PIC X(80).
PROCEDURE DIVISION.
2200-VALIDATE-DATE.
CALL 'DATEUTIL'
USING WS-TRANS-DATE
WS-FORMATTED-DATE
WS-DATE-RC
WS-DATE-MSG
END-CALL
IF WS-DATE-RC NOT = 0
* Business decision: log and skip, or escalate?
IF WS-DATE-RC = 4
* Warning: use default date and continue
MOVE WS-DEFAULT-DATE TO WS-FORMATTED-DATE
ELSE
* Error: record this transaction as rejected
MOVE WS-DATE-MSG TO WS-REJECT-REASON
PERFORM 2900-REJECT-TRANSACTION
END-IF
END-IF
.
Consistent Error Interface
Define a standard error interface structure that all programs in the system use:
* Standard error interface (copybook ERRIFACE.cpy)
01 ERROR-INTERFACE.
05 EI-RETURN-CODE PIC S9(4) COMP.
88 EI-SUCCESS VALUE 0.
88 EI-WARNING VALUE 4.
88 EI-ERROR VALUE 8.
88 EI-SEVERE VALUE 12.
88 EI-FATAL VALUE 16.
05 EI-ERROR-COUNT PIC S9(4) COMP.
05 EI-ERRORS.
10 EI-ERROR-ENTRY OCCURS 20 TIMES.
15 EI-ERR-CODE PIC X(8).
15 EI-ERR-SEV PIC 9.
15 EI-ERR-FIELD PIC X(30).
15 EI-ERR-MSG PIC X(80).
15 EI-ERR-DATA PIC X(50).
When every program in the system uses the same error interface, error handling becomes predictable and error information can flow seamlessly from the lowest-level utility to the highest-level controlling program.
Centralized Error Logging Service
In large systems, implement error logging as a separate service that all programs call:
* All programs call this centralized logger
CALL 'ERRLOGSV'
USING WS-LOG-REQUEST
ON EXCEPTION
* If even the logger fails, fall back to DISPLAY
DISPLAY 'LOGGER UNAVAILABLE: '
WS-LOG-REQUEST
END-CALL
The centralized logger writes to a standard log file (or DB2 table, or MQ queue) with a consistent format that operations monitoring tools can parse and alert on.
16.18 Best Practices Summary
Exception handling is not a feature you add at the end of development. It must be designed into the program from the start. Here are the essential best practices:
File Status: Always
Every file in every program must have a FILE STATUS variable. Every I/O operation must be followed by a check of that variable. There are no exceptions to this rule.
* REQUIRED for every file:
SELECT EVERY-FILE
ASSIGN TO EVERYFL
FILE STATUS IS WS-EVERY-STATUS.
Use 88-Level Conditions for Status Codes
Define 88-level condition names for every file status value you expect to encounter. This makes the code self-documenting:
01 WS-FILE-STATUS PIC XX.
88 FS-SUCCESS VALUE '00'.
88 FS-DUPLICATE VALUE '02'.
88 FS-EOF VALUE '10'.
88 FS-KEY-NOT-FOUND VALUE '23'.
88 FS-DISK-FULL VALUE '34'.
88 FS-NOT-EXISTS VALUE '35'.
88 FS-ALREADY-OPEN VALUE '41'.
Scope Terminators: Always
Always use explicit scope terminators (END-IF, END-EVALUATE, END-READ, END-WRITE, END-COMPUTE, END-CALL). This eliminates ambiguity about where exception phrases apply:
* GOOD: Clear scope
READ INPUT-FILE
AT END
SET WS-EOF TO TRUE
NOT AT END
ADD 1 TO WS-COUNT
END-READ
* BAD: Ambiguous scope with period termination
READ INPUT-FILE
AT END SET WS-EOF TO TRUE.
Error Limits
Production programs should have error limits that prevent runaway processing when data is corrupted:
01 WS-MAX-ERRORS PIC 9(5) VALUE 1000.
01 WS-ERROR-COUNT PIC 9(5) VALUE 0.
IF WS-ERROR-COUNT >= WS-MAX-ERRORS
DISPLAY 'ERROR LIMIT EXCEEDED'
PERFORM 9000-CONTROLLED-ABORT
END-IF
Controlled Shutdown
Never let a program crash without cleaning up. Always close files, write summary records, and set appropriate return codes:
9000-CONTROLLED-ABORT.
DISPLAY 'CONTROLLED ABORT INITIATED'
PERFORM 3000-TERMINATE
MOVE 16 TO RETURN-CODE
STOP RUN
.
Log Everything
Every error should be logged with enough information to diagnose the problem without needing to reproduce it: the timestamp, the program name, the paragraph where the error occurred, the file or data element involved, the actual data value that caused the error, and the record number or key.
Test the Error Paths
Error handling code that is never tested will fail when it is needed most. Create test data that exercises every error path: invalid data, missing files, full disks, duplicate keys, and out-of-range values.
Summary
This chapter covered the complete spectrum of COBOL error handling, from language-level features to platform-specific mechanisms:
- The DECLARATIVES section provides automatic interception of I/O errors through USE AFTER STANDARD ERROR/EXCEPTION procedures, triggered by the runtime before control returns to your program.
- File status codes are the fundamental mechanism for detecting I/O outcomes. The two-character status code covers successful completion (00-07), end-of-file (10-14), invalid key conditions (21-24), permanent errors (30-39), logic errors (41-49), and implementor-defined conditions (90-99).
- Inline exception phrases (ON SIZE ERROR, ON OVERFLOW, INVALID KEY, AT END) provide statement-level error handling that keeps the error response close to the statement that caused it.
- The COBOL 2002 RAISE/RESUME mechanism introduces structured exception handling with user-definable exception classes, explicit exception raising, and controlled resumption.
- IBM Language Environment condition handling operates beneath the COBOL level, intercepting hardware and software conditions with configurable severity-based responses.
- Return codes communicate success or failure between programs, following the standard 0/4/8/12/16 convention.
- Common abend codes (S0C7, S0C4, S0C1, S0CB, S322, S806) each have specific causes and specific prevention techniques.
- Error logging patterns provide structured, diagnosable records of every error encountered during processing.
- Defensive programming -- validating input, initializing variables, checking boundaries, guarding against division by zero, and checking file status after every I/O operation -- prevents the majority of production errors.
- A production error handling framework combines all these techniques into a cohesive program structure with error limits, controlled shutdown, and comprehensive summary reporting.
The difference between a junior COBOL programmer and a senior one is often measured not by the business logic they write, but by how thoroughly they handle the cases when things go wrong. In production systems that process millions of transactions daily, robust error handling is not optional -- it is the foundation of reliability.
Exercises
-
File Status Exercise: Write a program that opens an indexed file with FILE STATUS, attempts to READ a record with a non-existent key, and handles the resulting status code 23 with a meaningful message.
-
Arithmetic Protection: Write a program that reads a file of transaction records, computes a running average of the amounts, and handles division by zero (for the first record) and size overflow using ON SIZE ERROR.
-
DECLARATIVES Practice: Write a program with DECLARATIVES that handles errors on three different files (input, output, and log), each with its own declarative section.
-
Error Limit Framework: Extend the production framework from Section 16.13 to include a percentage-based error limit (abort if more than 5% of records have errors) in addition to the absolute error limit.
-
Comprehensive Validation: Write a validation subprogram that accepts a customer record, validates every field (customer ID, name, address, date of birth, account balance), and returns both a return code and a table of error messages describing every validation failure found.