Explained: CICS Error Handling

Codelooru cics error handling

A CICS transaction reads a customer record. The record does not exist. The program does not check the response code. It continues with uninitialised Working Storage, writes garbage to a VSAM file, and returns a confirmation to the screen. The customer's record is now corrupt. Nobody knows yet.

Error handling in CICS is not optional. Every CICS command can fail. Files return `NOTFND`. DB2 returns lock timeouts. Programs abend with `ASRA`. The difference between a well-built CICS application and a fragile one is almost entirely in how it handles these situations: whether it detects them, how it responds, and whether it leaves the data in a consistent state when it cannot proceed.

This post assumes you have read Architecture: CICS and Explained: COBOL. It covers the two layers of CICS error handling: exception conditions returned by CICS commands, and abends that terminate tasks. It then covers syncpoints and backout: the mechanism that keeps data consistent when things go wrong.


Two Kinds of Failure

CICS distinguishes between two levels of error, and treating them the same is a common beginner mistake.

An exception condition is a non-fatal outcome from a CICS command. `NOTFND` when a file read finds no matching record. `LENGERR` when a length parameter is out of range. `NOTAUTH` when the user does not have access to the requested resource. These are expected, recoverable situations. The command did not succeed, but the program is still running and can take corrective action.

An abend (abnormal end) is a fatal failure that terminates the task. A program check (`ASRA`). A runaway task caught by the interval control timer (`AICA`). An explicit `EXEC CICS ABEND` issued by the program itself. An unhandled exception condition that CICS escalates to an abend because the program provided no handler. Abends end the task immediately, trigger a backout of uncommitted changes, and optionally produce a transaction dump for diagnosis.

The correct handling strategy differs for each. Exception conditions should be anticipated and handled in the program logic. Abends should be caught by a last-resort handler that logs the failure, rolls back cleanly, and returns a meaningful error to the user or caller.


The EIB: Execution Interface Block

Every CICS task has an EIB (Execution Interface Block): a CICS-managed control block that describes the current state of the task. CICS updates the EIB before and after every command. The program can read EIB fields at any point.

The most important EIB fields for error handling are:

  • `EIBRESP`: the primary response code from the last CICS command. `DFHRESP(NORMAL)` (decimal 0) means success. Any other value identifies the exception condition that occurred.
  • `EIBRESP2`: the secondary response code, providing a more specific reason within the primary condition. `EIBRESP` of `NOTFND` might have different `EIBRESP2` values depending on whether the key was not found in a KSDS or the RRN was out of range in an RRDS.
  • `EIBFN`: a two-byte code identifying which CICS command was last executed. Used in error routines to determine what the program was doing when it failed.
  • `EIBTRNID`: the four-character transaction ID of the current task.
  • `EIBTASKN`: the task number, a unique identifier for the current task within the region.
  • `EIBCALEN`: the length of the commarea passed to this program. Zero if no commarea was passed.
  • `EIBRLDBK`: set to `'1'` if the task's unit of work has been rolled back (backed out) by CICS. A program can test this to avoid attempting further resource updates after a backout.

The `RESP` and `RESP2` options on CICS commands are simply a mechanism to copy `EIBRESP` and `EIBRESP2` into named Working Storage fields at the moment the command executes. Using `RESP(WS-RESP)` is equivalent to checking `EIBRESP` immediately after the command, but is safer because it captures the value before any subsequent command overwrites the EIB.


Handling Exception Conditions: RESP

The modern and recommended approach to exception condition handling is to include `RESP` (and optionally `RESP2`) on every CICS command and check the result before proceeding. This is inline handling: the program tests for specific conditions immediately after each command and takes the appropriate path.

EXEC CICS READ
    FILE('ACCOUNTS')
    INTO(WS-ACCOUNT-RECORD)
    RIDFLD(WS-ACCOUNT-KEY)
    RESP(WS-RESP)
    RESP2(WS-RESP2)
END-EXEC

EVALUATE WS-RESP
    WHEN DFHRESP(NORMAL)
        PERFORM PROCESS-ACCOUNT
    WHEN DFHRESP(NOTFND)
        PERFORM ACCOUNT-NOT-FOUND
    WHEN DFHRESP(NOTAUTH)
        PERFORM NOT-AUTHORIZED
    WHEN OTHER
        MOVE WS-RESP  TO WS-ERROR-RESP
        MOVE WS-RESP2 TO WS-ERROR-RESP2
        PERFORM UNEXPECTED-ERROR
END-EVALUATE

The `DFHRESP` function translates the condition name to its numeric value at compile time. Always use `DFHRESP(name)` rather than hardcoded numbers in comparisons: the numeric values are internal constants that IBM reserves the right to change between CICS releases. Using the symbolic name keeps the code stable across versions.

The `WHEN OTHER` branch is mandatory for robust code. Any CICS command can return unexpected conditions. Leaving `WHEN OTHER` out means an unanticipated condition falls through with no handling, leaving the program in an undefined state.

When `RESP` is specified on a command, CICS does not raise an abend for any exception condition that occurs. The program receives control regardless of the outcome, with `WS-RESP` set to the condition code. This is why `RESP` handling requires the `EVALUATE` block: without it, a failed command is silently ignored.


Handling Exception Conditions: HANDLE CONDITION

HANDLE CONDITION is the older mechanism, used extensively in CICS programs written before the `RESP` option became the standard. It establishes a label-based trap: when a named condition occurs on any subsequent command, CICS transfers control to the specified paragraph rather than returning inline.

PROCEDURE DIVISION.
MAIN-LOGIC.
    EXEC CICS HANDLE CONDITION
        NOTFND(ACCOUNT-NOT-FOUND)
        NOTAUTH(NOT-AUTHORIZED)
        ERROR(UNEXPECTED-ERROR)
    END-EXEC

    EXEC CICS READ
        FILE('ACCOUNTS')
        INTO(WS-ACCOUNT-RECORD)
        RIDFLD(WS-ACCOUNT-KEY)
    END-EXEC

    *> If we reach here, READ succeeded
    PERFORM PROCESS-ACCOUNT
    EXEC CICS RETURN END-EXEC.

ACCOUNT-NOT-FOUND.
    *> Handle the NOTFND condition
    PERFORM SEND-NOT-FOUND-MSG
    EXEC CICS RETURN END-EXEC.

NOT-AUTHORIZED.
    PERFORM SEND-AUTH-ERROR-MSG
    EXEC CICS RETURN END-EXEC.

HANDLE CONDITION has scope across the entire program from the point it is issued. A single HANDLE CONDITION command can cover many subsequent CICS commands. This is both its advantage (less repetitive code) and its weakness: when an error fires, it can be hard to tell which command caused it, because the handler catches conditions from any subsequent command, not just the next one.

HANDLE CONDITION and `RESP` can be mixed, but mixing them carefully requires understanding their interaction. If `RESP` is specified on a command, CICS uses `RESP` and does not invoke the HANDLE CONDITION trap for that command. If `RESP` is not specified, the active HANDLE CONDITION trap applies. Most modern programs use `RESP` exclusively and avoid HANDLE CONDITION entirely.

The `ERROR` condition in HANDLE CONDITION is a catch-all: it fires for any exception condition not explicitly named in the HANDLE CONDITION list. It is the HANDLE CONDITION equivalent of `WHEN OTHER` in an `EVALUATE`.


Abend Codes

When a task ends abnormally, CICS assigns a four-character abend code. The code is the primary diagnostic identifier: it tells the operator and developer what went wrong and which CICS component detected the failure.

The structure of CICS abend codes is meaningful. The first character is always `A`. The middle two characters identify the domain that issued the abend. The last character provides additional detail. This is why an `ASRA` abend means the System Recovery Program (SR) caught a program check (A): `A` prefix, `SR` domain, `A` qualifier for program interrupt.

The most common abend codes in production CICS:

  • `ASRA`: a program check. The most common CICS abend. Caused by a data exception (S0C7 — moving non-numeric data into a numeric field), a protection exception (S0C4 — writing to storage the program does not own), an operation exception (S0C1 — executing invalid instructions), or other hardware-detected errors. `ASRA` is almost always a programming bug.
  • `AICA`: runaway task. The task consumed more CPU time than allowed by the `ICVR` (Interval Control Value Runaway) parameter between CICS service calls. Usually caused by an infinite loop or a tight computational loop that never issues a CICS command. CICS monitors CPU consumption between commands; a program that loops without calling CICS exceeds the interval and gets `AICA`.
  • `ASRB`: a program check in a non-CICS module. Similar to `ASRA` but the fault occurred in code outside the CICS application environment, such as a Language Environment routine or a vendor module.
  • `AEY9`: DB2 connection not available. The CICS-DB2 attachment could not establish a thread for the request. Caused by DB2 being unavailable, the thread limit being exceeded, or the transaction not being authorized to connect to the DB2 subsystem.
  • `AKCS`: transaction security failure. The user ID running the transaction is not authorized to execute it per RACF.
  • `ATNI`: terminal not connected. The terminal associated with the task disconnected during execution.
ABEND CODE STRUCTURE — e.g. A S R A A Always 'A' S R Domain: SR = System Recovery, IC = Interval Control, EY = DB2 A Qualifier: specific error type within domain Code Cause Typical root cause ASRA Program check (S0C4, S0C7, S0C1) Bad data in numeric field, storage overrun AICA Runaway task — CPU limit exceeded Infinite loop, no CICS calls in tight loop AEY9 DB2 thread not available DB2 down, thread limit hit, not authorized ASRB Program check in non-CICS module LE runtime, vendor module fault AKCS Transaction security failure RACF denied access to transaction Figure 1: Abend code structure and the five most common codes in production CICS.

Handling Abends: HANDLE ABEND

HANDLE ABEND establishes a last-resort error handler for the current logical level. If the task abends and a HANDLE ABEND has been established, CICS transfers control to the specified label or program rather than terminating the task immediately. This gives the program an opportunity to log the failure, notify an operator, roll back data, and return a meaningful error message.

PROCEDURE DIVISION.
MAIN-LOGIC.
    EXEC CICS HANDLE ABEND
        LABEL(ABEND-HANDLER)
        RESP(WS-RESP)
    END-EXEC

    *> Main processing logic
    PERFORM VALIDATE-INPUT
    PERFORM UPDATE-ACCOUNT
    PERFORM UPDATE-AUDIT-LOG

    EXEC CICS RETURN END-EXEC.

ABEND-HANDLER.
    *> Log the failure
    EXEC CICS WRITE OPERATOR
        TEXT('Transaction failed - rolling back')
    END-EXEC

    *> Roll back all uncommitted changes
    EXEC CICS SYNCPOINT ROLLBACK END-EXEC

    *> Return an error response to the caller
    MOVE 'E' TO CA-STATUS
    EXEC CICS RETURN END-EXEC.

HANDLE ABEND is scoped to the logical level at which it is established. A HANDLE ABEND in a level 1 program catches abends in that program. If the program LINKs to a level 2 program and that program abends without its own HANDLE ABEND, control propagates up to the level 1 handler. This propagation makes a top-level HANDLE ABEND a useful safety net for the entire call chain.

Inside the abend handler, EIB fields can be read, but some are no longer reliable: `EIBRESP` and `EIBRESP2` reflect the last successful command before the abend, not the abend itself. The abend code is available via `EXEC CICS ASSIGN ABCODE(WS-ABCODE)`. Capturing the abend code and the `EIBFN` value (which command was executing) is the minimum useful logging from an abend handler.

A HANDLE ABEND handler must itself be written defensively. If the handler abends, there is no further recovery: CICS terminates the task immediately. A handler that issues CICS commands should use `RESP` on every one of them.


Syncpoints and Backout

CICS maintains a unit of work (UOW) for every task. The UOW tracks all recoverable resource changes the task has made since its last commit: VSAM file updates, DB2 row changes, MQ message puts. When the task commits, those changes become permanent and visible to other tasks. When the task backs out, those changes are reversed as if they never happened.

A syncpoint is the act of committing the current UOW and starting a new one. CICS issues an automatic syncpoint when a task terminates normally (via `EXEC CICS RETURN` at logical level 1). The program can also issue an explicit syncpoint mid-transaction:

EXEC CICS SYNCPOINT
    RESP(WS-RESP)
END-EXEC

An explicit syncpoint is appropriate when a transaction does a large amount of work that should be committed in stages rather than all at once. A batch-style CICS transaction that processes thousands of records might commit every hundred records to avoid holding locks on all of them simultaneously and to reduce the amount of backout work needed if it fails late in processing.

A syncpoint rollback backs out all changes made since the last syncpoint without terminating the task:

EXEC CICS SYNCPOINT ROLLBACK
    RESP(WS-RESP)
END-EXEC

This is the explicit mechanism for programmatic backout: the program detects an error, decides it cannot proceed, issues `SYNCPOINT ROLLBACK` to undo all its changes, and then returns an error to the caller. The task terminates cleanly (no abend dump, no error messages on the console), but all resource updates are reversed. This is the preferred pattern for recoverable business errors: a payment that fails validation should roll back, not abend.

When a task abends, CICS performs an automatic backout as part of abend processing. The task does not need to issue `SYNCPOINT ROLLBACK` explicitly: CICS uses its system log to reverse every recoverable resource change the task made since its last syncpoint. This automatic backout is what makes CICS transactions safe: a program bug that causes an `ASRA` mid-update does not leave a half-updated VSAM file or a partially committed DB2 row.

START VSAM update: account balance DB2 update: transaction log VSAM update: audit record EXEC CICS RETURN Auto syncpoint — all changes committed All 3 updates permanent SYNCPOINT ROLLBACK Program detected an error — rolls back All 3 updates reversed Task ends cleanly, no dump ASRA ABEND Program check mid-update Auto backout by CICS All updates reversed Transaction dump produced Figure 2: Three outcomes for the same unit of work — commit, rollback, and abend backout.

Intermediate Syncpoints in Long Transactions

A task that updates many records in a single unit of work holds locks on all of them until it commits. In a high-concurrency CICS region, this creates contention: other tasks trying to access those same records must wait. Intermediate syncpoints break the work into smaller units, each of which commits and releases its locks before the next unit begins.

The trade-off is recovery granularity. If the task fails after its third intermediate syncpoint, CICS can only back out changes since that last syncpoint. The changes committed in the first three syncpoints are permanent. The program must be designed to handle this: it needs to know where it left off and resume from there rather than restarting from the beginning.

This pattern is common in CICS transactions that process queues or batches of work: read a batch of records from a transient data queue, process them, commit, read the next batch, process them, commit. Each commit is a checkpoint. A failure mid-batch only loses that batch, not all preceding work.


The Transaction Dump

When a CICS task abends, CICS optionally writes a transaction dump to the spool. The dump contains a snapshot of the task's state at the time of failure: the contents of all DSA storage allocated to the task, the EIB, the program link stack (which programs were active and at what logical levels), register contents, and a trace of recent CICS activity.

Transaction dumps are identified by a four-character dump code. For abends, the dump code is the abend code itself. Dumps are written to a CICS dump dataset or to the transient data queue `CSDL`, and are browsable using the CEDF (CICS Execution Diagnostic Facility) transaction or the IPCS dump analysis tool.

Reading a transaction dump to diagnose an `ASRA` follows a standard sequence: find the EIB to identify the transaction and the last CICS command executed (`EIBFN`), find the program storage to read the Working Storage fields at the time of failure, and locate the instruction address from the program check PSW (Program Status Word) to identify exactly which line of the compiled program caused the fault. IBM's COBOL compiler produces a listing that maps instruction addresses to source line numbers, making the exact failing statement identifiable.

Programs can also issue a dump explicitly, without abending:

EXEC CICS DUMP TRANSACTION
    DUMPCODE('MYCD')
    RESP(WS-RESP)
END-EXEC

This is useful in error handlers that want a dump for diagnostic purposes but still need to roll back cleanly and return an error to the user rather than terminating abnormally.


The CEDF Transaction

CEDF (CICS Execution Diagnostic Facility) is CICS's interactive debugger. It intercepts a running transaction at every CICS command boundary, displaying the command, its parameters, and its response before and after execution. The developer can inspect Working Storage, modify field values, and step through the transaction one CICS command at a time.

CEDF is the primary tool for diagnosing unexpected condition codes in development and test environments. A transaction that is returning `NOTAUTH` unexpectedly can be run under CEDF to see exactly which command returned the condition and what the RACF check was on. A transaction that is getting `ASRA` can be stepped to the point of failure to see what was in Working Storage immediately before the program check.

CEDF is enabled on a terminal by running the `CEDF` transaction before the transaction to be debugged. It attaches to the next transaction run from the same terminal. In a multi-region environment where the AOR is remote from the TOR, CEDF must be invoked in the AOR where the program executes, not in the TOR where the terminal session lives.


A Complete Error Handling Pattern

Production CICS programs typically combine all three mechanisms: `RESP` for command-level condition handling, `HANDLE ABEND` for last-resort recovery, and `SYNCPOINT ROLLBACK` for clean backout. Here is a skeleton that shows how they fit together:

PROCEDURE DIVISION.
MAIN-LOGIC.
    *> Establish last-resort abend handler first
    EXEC CICS HANDLE ABEND
        LABEL(ABEND-HANDLER)
    END-EXEC

    *> Main business logic with inline RESP checking
    PERFORM VALIDATE-INPUT
    PERFORM UPDATE-ACCOUNT
    PERFORM UPDATE-AUDIT

    *> All successful — commit and return
    EXEC CICS RETURN END-EXEC.

UPDATE-ACCOUNT.
    EXEC CICS REWRITE
        FILE('ACCOUNTS')
        FROM(WS-ACCOUNT-RECORD)
        LENGTH(LENGTH OF WS-ACCOUNT-RECORD)
        RESP(WS-RESP)
    END-EXEC

    EVALUATE WS-RESP
        WHEN DFHRESP(NORMAL)
            CONTINUE
        WHEN DFHRESP(NOTFND)
            MOVE 'N' TO CA-STATUS
            EXEC CICS SYNCPOINT ROLLBACK END-EXEC
            EXEC CICS RETURN END-EXEC
        WHEN OTHER
            *> Unexpected — force abend for dump
            EXEC CICS ABEND
                ABCODE('UACC')
                NODUMP
            END-EXEC
    END-EVALUATE.

ABEND-HANDLER.
    *> Capture what happened
    EXEC CICS ASSIGN
        ABCODE(WS-ABCODE)
    END-EXEC

    *> Roll back all changes
    EXEC CICS SYNCPOINT ROLLBACK
        RESP(WS-RESP)
    END-EXEC

    *> Notify operator
    EXEC CICS WRITE OPERATOR
        TEXT('Abend in ACCTUPD')
        RESP(WS-RESP)
    END-EXEC

    *> Return error to caller via commarea
    MOVE 'E' TO CA-STATUS
    EXEC CICS RETURN END-EXEC.

This pattern covers the full spectrum: expected business errors are handled inline with `RESP` and resolved with `SYNCPOINT ROLLBACK`; unexpected failures are caught by the abend handler, which rolls back, logs, and returns cleanly without leaving the region in a degraded state or the data in an inconsistent one.


Summary

CICS error handling operates at two levels. Exception conditions are the normal, anticipated outcomes of CICS commands: file not found, user not authorized, length error. Handle them inline with `RESP` and `EVALUATE`, covering both expected conditions and the `WHEN OTHER` fallback. Abends are abnormal terminations: program checks, runaway tasks, resource failures. Catch them with `HANDLE ABEND` at the top of the program.

Syncpoints and backout are the mechanism that keeps data consistent through all of this. A `SYNCPOINT ROLLBACK` undoes uncommitted work without terminating the task. An abend triggers automatic backout by CICS without any program involvement. Either way, a CICS transaction that fails does not leave partial updates in place. That guarantee is fundamental to building reliable applications on the platform.

The EIB, the transaction dump, and CEDF are the three diagnostic tools. The EIB tells you what happened. The dump tells you the full state at the time of failure. CEDF lets you watch it happen interactively. Together they make CICS failures, while never welcome, at least tractable.

Part of the Mainframe Decoded series — IBM Z and z/OS, clearly explained for engineers.



×