COBOL Troubleshooting
COPYBOOK version mismatch
Troubleshooting guide for COPYBOOK version mismatch. Logic bugs do not abend — the program runs to completion and produces wrong results, so they are found by control totals, not dumps.
What it means
- COBOL control flow (PERFORM, GO TO, CALL) is paragraph-based, so a misplaced period or wrong paragraph range silently changes what executes.
- Parameter bugs between programs (CALL ... USING vs LINKAGE SECTION) corrupt data without any error message.
- Copybook and name collisions cause the compiler to accept code that does something different from what the programmer intended.
Common causes
- Infinite loop: PERFORM UNTIL condition where the condition field is never updated inside the loop, or the update is in a paragraph that is never reached.
- PERFORM PARA-A THRU PARA-B executes every paragraph in between, including paragraphs the programmer thought were separate.
- Nested PERFORM: an inner PERFORM ... THRU range that overlaps the outer range causes paragraphs to execute twice or be skipped.
- CALL USING passes 3 items but the called program LINKAGE SECTION defines 4 — the 4th item reads whatever follows in memory.
- Copybook updated in one program but not recompiled in the caller — layout mismatch between CALLER and CALLEE.
- Duplicate paragraph or data names: the compiler uses the first definition; the second is silently ignored (warning only).
- 88-level condition name with overlapping values, e.g. 88 VALID VALUE 1 THRU 5 followed by 88 ALSO-VALID VALUE 5 — value 5 sets both.
- INITIALIZE WS-GROUP clears every subordinate field including counters and flags the programmer wanted to keep.
- STRING ... WITH POINTER: pointer not reset to 1 before the next STRING, so data is written past the intended position or overflows.
- UNSTRING with ALL delimiter phrase missing: consecutive delimiters create empty items that shift the receiving fields.
How to diagnose
- For loops: DISPLAY a counter every 1000 iterations, or check whether the loop-exit field is actually modified inside the loop body.
- For PERFORM ranges: list the paragraphs between the THRU endpoints — every one of them executes, including fall-through paragraphs after the last one if there is no GOBACK/STOP RUN.
- For CALL mismatches: compare the USING list against the LINKAGE SECTION item by item — count, order, and PIC sizes must match exactly.
- Compile with LIST and XREF and check for duplicate-name warnings; treat every warning as a bug.
- For 88-levels: DISPLAY the field value in hex when the condition misbehaves — the value is often not what the tester assumed.
How to fix it
- Replace PERFORM ... THRU with explicit PERFORM paragraph-name (no THRU) or use inline PERFORM ... END-PERFORM blocks.
- Make CALL USING and LINKAGE SECTION agree exactly; pass a single group item instead of many fields to reduce mismatch risk.
- Recompile every program that copies a changed copybook — automate this in the build so stale modules cannot ship.
- Reset STRING pointers (MOVE 1 TO WS-PTR) before each STRING, and check ON OVERFLOW.
- Split INITIALIZE into targeted MOVEs, or INITIALIZE only the subgroup that really needs clearing.
Example: Safe loop and parameter patterns
PERFORM UNTIL EOF-FLAG = "Y"
READ INPUT-FILE
AT END MOVE "Y" TO EOF-FLAG
NOT AT END ADD 1 TO WS-READ-COUNT
END-READ
END-PERFORM.
*
CALL "SUBPROG" USING WS-CUST-GROUP
ON EXCEPTION
DISPLAY "CALL FAILED"
END-CALL.
Inline PERFORM keeps loop control visible; passing one group item keeps CALL and LINKAGE SECTION in sync.
Interview tip
- Q: A program produces wrong totals but never abends. It uses PERFORM ... THRU and CALLs a subprogram. Where do you look first?
- A: I check the PERFORM THRU range first, because it executes every paragraph between the endpoints — often more than intended. Then I compare the CALL USING list against the subprogram LINKAGE SECTION field by field, since a count or size mismatch silently corrupts data.
Prevention checklist
- Prefer inline PERFORM ... END-PERFORM over paragraph THRU ranges.
- Pass one group item on CALL USING instead of long field lists.
- Compile with SSRANGE and TEST options in QA to catch subscript and logic errors early.
- Reconcile control totals (record counts, hash totals) between input and output on every run.
