MainframeMaster

COBOL Robust Programming

Robust programming in COBOL means writing code that behaves correctly even when data is bad, resources are missing, or operations fail. It relies on defensive coding: validating input, checking every file and command response, validating subscripts and indexes, and handling errors explicitly. This page covers how to make your COBOL programs more reliable through validation, error handling, and defensive traps.

Explain Like I'm Five: What Is Robust Programming?

Robust programming is like checking that the door is locked and the lights work before you leave the house. In a program, it means: "Did the read work?" "Is this number in the right range?" "Is the subscript valid?" Instead of assuming everything is fine, you check. When something is wrong, you handle it (show a message, skip the record, or stop safely) instead of letting the program crash or produce wrong answers.

Defensive Coding and Defensive Traps

Defensive coding is the habit of checking conditions that could be wrong before you use them. A defensive trap is a specific check you add to catch invalid or unexpected situations. For example: check file status after every READ; validate that a subscript is between 1 and the table size before using it; check that a divisor is not zero before DIVIDE. Traps are often added around risky areas: file I/O, CALL and CICS commands, STRING/UNSTRING, arithmetic, EVALUATE and IF, and SEARCH. The goal is to fail in a controlled way (with a clear error or message) instead of abending or corrupting data.

Areas for defensive traps
AreaWhat to checkPurpose
File I/OFile status after OPEN, READ, WRITE, REWRITE, CLOSEHandle EOF, errors, invalid key
Subscripts and indexesBounds before using (e.g. 1 to N)Avoid subscript out of range
CALL / CICSReturn code or EIBRESPHandle missing program or command failure
ArithmeticDivide by zero, overflow, valid operandsAvoid abends and wrong results
Input dataLength, type (NUMERIC), range, allowed valuesReject bad data before use

Data Validation

Validate all data that comes from outside your program: user input, file records, parameters from CALL, and CICS commareas. Validate as early as possible—ideally at the point where the data enters your program or at the start of the procedure that uses it. Use multiple layers: field-level (type, length, range), record-level (all required fields present and consistent), and cross-record or cross-field where needed (e.g. start date before end date).

Use COBOL class conditions: NUMERIC to ensure a field contains only digits (and sign if applicable), ALPHABETIC for letters and spaces, and ALPHANUMERIC if you allow both. Use relation conditions for ranges: IF WS-AMOUNT >= 0 AND WS-AMOUNT <= 999999.99. Use 88-level condition names for allowed values: define 88 VALID-STATUS VALUES 'A' 'B' 'C' and then IF VALID-STATUS. That makes the allowed set explicit and easy to change.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
01 WS-INPUT. 05 WS-ID PIC 9(6). 05 WS-STATUS PIC X(1). 88 VALID-STATUS VALUES 'A' 'B' 'C'. 05 WS-AMT PIC S9(7)V99. *> Field validation IF WS-ID IS NOT NUMERIC MOVE 'Invalid ID' TO WS-MESSAGE PERFORM ERROR-OUT END-IF IF NOT VALID-STATUS MOVE 'Invalid status' TO WS-MESSAGE PERFORM ERROR-OUT END-IF IF WS-AMT < 0 OR WS-AMT > 999999.99 MOVE 'Amount out of range' TO WS-MESSAGE PERFORM ERROR-OUT END-IF

File and Command Response Checking

After every file operation (OPEN, READ, WRITE, REWRITE, DELETE, CLOSE), check the file status. If it is not 00 (and not 10 for end-of-file when that is expected), do not assume the operation succeeded. Branch to error handling: log the status, set a message, and either retry, skip the record, or terminate cleanly. Similarly, in CICS programs check EIBRESP (or RESP/RESP2) after every EXEC CICS command that can fail. Use HANDLE CONDITION or NOHANDLE with explicit checks so that unexpected responses do not cause an abend. Robust programs never assume success; they always branch on the actual response.

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
READ CUST-FILE AT END SET WS-EOF TO TRUE END-READ IF WS-FILE-STATUS = '00' PERFORM PROCESS-RECORD ELSE IF WS-FILE-STATUS = '10' PERFORM END-OF-FILE ELSE DISPLAY 'READ error ' WS-FILE-STATUS PERFORM ABEND-RECOVERY END-IF END-IF

Subscript and Index Validation

Before using a subscript or index to access a table (OCCURS), ensure it is within bounds. If the table has OCCURS 12 TIMES, the subscript must be between 1 and 12 (inclusive) for standard 1-based subscripting. If you use a variable that could be wrong (e.g. from input or from a computation), test it: IF WS-SUB >= 1 AND WS-SUB <= 12 before using WS-SUB as a subscript. Invalid subscripts can overwrite storage or cause abends. The same applies to indexes: set and validate them before use in SEARCH or in reference modification.

Arithmetic and Divide-by-Zero

Before DIVIDE or any operation that could divide by zero, check the divisor. If the divisor is zero, skip the operation or use a default and set an error flag. On some platforms, division by zero causes an abend; on others you may get an overflow or undefined result. Also consider overflow: very large results may not fit in the receiving field. Use ON SIZE ERROR (or equivalent) where available and handle the error path. Validate numeric operands (e.g. NUMERIC) when they come from input so you do not perform arithmetic on non-numeric data.

Error Handling and Recovery

When you detect an error, decide what the program should do: display or log the error, set a return code, skip the record, retry, or terminate. Use a consistent approach: e.g. a single ERROR-PARAGRAPH that logs the condition and either continues or exits. For batch, you might write bad records to an error file and continue; for CICS, you might send a message to the user and RETURN. Document the severity (e.g. warning vs critical) so operations know whether to investigate. Avoid silently ignoring errors; at least log them.

Step-by-Step: Adding Validation to an Input Record

  1. List every field that comes from the input (file, user, or caller). For each, define allowed type (numeric, alphabetic, alphanumeric), length, and range or allowed values.
  2. At the start of processing, validate type (e.g. NUMERIC for numeric fields), then length (e.g. INSPECT or LENGTH), then range or 88-level values. If any check fails, set an error message and branch to error handling; do not use the field in business logic.
  3. Optionally use 88-level condition names for status or code fields so IF VALID-STATUS is clear and maintainable.

Best Practices

Test Your Knowledge

Test Your Knowledge

1. Defensive coding in COBOL emphasizes:

  • Ignoring errors
  • Checking for errors and invalid conditions before they cause failures
  • Using GO TO only
  • Skipping validation

2. To ensure a field contains only digits you can use:

  • MOVE only
  • IF field IS NUMERIC
  • READ only
  • No check needed

3. After every READ you should:

  • Assume success
  • Check file status and branch on 00, 10, or error
  • Close the file
  • Ignore AT END