In the z/OS ecosystem, a return code is more than a simple error number. It is a compact contract between a called component and its caller: the component reports how it completed, and the caller decides whether to continue, branch, retry, terminate, or raise an operational alert.
This article describes the practical mechanics of return codes in z/OS, how they interact with JCL, how TSO/E batch execution through the Terminal Monitor Program (TMP) affects return-code propagation, and why edge cases such as large, negative, Language Environment, and z/OS UNIX return codes require care.
Architectural Definition and Mechanics
A return code is a numeric value returned by a program, command processor, system service, utility, or job step to describe the outcome of an operation. The invoking environment can then inspect that value and decide what to do next.
Typical interpretations are:
| Return code | Common meaning |
|---|---|
| 0 | Successful completion |
| 4 | Completion with warning or minor exception |
| 8 | Error; requested work may be incomplete |
| 12 | Severe error; downstream processing should usually be bypassed |
| 16 | Very severe or terminal error |
These values are common, but they are not universal law. Many IBM utilities and services use a severity progression based on multiples of four, but every interface, subsystem, utility, and programming environment can define its own return-code meanings. A return code value is only authoritative when interpreted in the context of the component that produced it.
Register 15 and the linkage convention
At the program-linkage level, z/OS software commonly uses general purpose register 15 (R15) in two different phases of a call:
- On entry to a called program or routine, R15 often contains the entry-point address.
- On return, R15 commonly contains the return code supplied to the caller.
In assembler terms, a called routine typically returns control through register 14, and the caller inspects R15 to determine the outcome. This is a standard IBM linkage convention used in many z/OS calling interfaces.
Multiples of four: useful convention, not universal standard
The familiar 0, 4, 8, 12, and 16 pattern is widely used because it gives operators and batch designers a predictable severity scale. However, z/OS components also use return codes outside this pattern. Some interfaces return 20, 24, or larger values. Others pair a return code with a reason code. Some language runtimes and utilities impose additional translation rules.
This matters operationally. An RC=8 from one utility might mean a recoverable data issue, while another utility might use RC=8 to mean a syntax error or failed allocation. The return code is a signal, not the diagnosis.
JCL Integration and Condition Processing
In Job Control Language (JCL), return codes are central to conditional workflow execution. A job step completes, the system records a step completion code, and later steps can test that code to decide whether to run.
Historically, this was done with the COND parameter. Later JCL introduced structured IF/THEN/ELSE/ENDIF constructs, which are easier to read and maintain. Both mechanisms still depend on completion information produced by earlier steps.
Legacy control: the COND parameter
The COND parameter controls whether a step should be bypassed. This is the part that often confuses new JCL readers: a true COND expression means do not execute this step.
Example:
//STEP02 EXEC PGM=MYPROG,COND=(4,LT,STEP01)This means: compare 4 with the return code from STEP01. If 4 < STEP01.RC is true, bypass STEP02.
So if STEP01 ends with RC=8, the expression 4 < 8 is true, and STEP02 is skipped.
Modern control: IF/THEN/ELSE/ENDIF
Structured conditional processing avoids much of the inverse logic of COND:
//STEP01 EXEC PGM=PROGA
//*
//TESTSTEP IF (STEP01.RC = 0) THEN
//STEP02 EXEC PGM=PROGB
// ENDIFThis is clearer: run the PROGB program only if the former step completed with RC=0.
JCL conditional processing is powerful enough for job-step flow control, but it should not be mistaken for a general procedural programming language. It evaluates job-step and execution-state conditions such as return codes, ABEND status, and whether a step ran.
TSO/E Batch Execution and the Terminal Monitor Program
When return codes are produced inside a TSO/E environment, the behaviour depends on the Terminal Monitor Program (TMP) entry point used to run the command or program.
The TMP is the TSO/E component that provides the interface between the user, command processors, and the TSO/E control program. It obtains commands, gives control to command processors, and monitors command execution.
In foreground TSO/E, the TMP is invoked as part of the logon environment. In batch TSO/E, it is commonly invoked through JCL. A typical batch TSO/E step looks like this:
//TSOSTEP EXEC PGM=IKJEFT01
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
LISTCAT LEVEL(SOME.DATASET.PREFIX)
/*SYSTSIN supplies commands to the TMP. SYSTSPRT receives terminal-style output.
IKJEFT01: the traditional batch TMP entry point
IKJEFT01 is the classic TMP entry point used to run TSO/E commands in the background.
Its return-code behaviour is important:
- If a command or program returns a non-zero return code,
IKJEFT01saves that code and continues processing the next command. - The final return code presented by the step is effectively influenced by the last command processed.
- Therefore, an earlier non-zero return code can be overwritten or obscured by a later command.
- If a command or program ABENDs,
IKJEFT01terminates the job step normally and placesRC=12in register 15.
The operational hazard is that a failing command may not determine the final job-step return code if later commands continue and return a different code.
IKJEFT1A: terminate on directly returned non-zero codes
IKJEFT1A changes the behaviour. When a directly invoked command, program, or REXX exec returns a non-zero return code, IKJEFT1A saves that code in R15 and terminates.
This makes it more suitable when batch control should stop at the first directly detected failure.
However, the behaviour has important boundaries:
- Non-zero return codes from CLISTs do not necessarily affect R15 in the same way.
- Return codes from programs not given control directly by
IKJEFT1Amay not be propagated as expected. - ABEND behaviour is not simply “convert everything to RC=12 or RC=16.”
For ABENDs, IBM documents more specific behaviour. A system ABEND under IKJEFT1A can cause the job step to terminate with system completion code X'04C', while the relevant completion information is returned in R15. User ABEND handling is also completion-code based rather than a simple severity-scale return-code conversion.
IKJEFT1B: stricter ABEND propagation
IKJEFT1B is stricter still. Like IKJEFT1A, it terminates when a directly processed command, program, or REXX exec returns a non-zero return code and saves that code in R15.
The major operational difference is ABEND behaviour. If a command or program processed by IKJEFT1B ends with a system or user ABEND, the job step is caused to terminate with system completion code X'04C', and the command or program completion code is returned in R15.
For production batch work, this behaviour can be preferable because it makes abnormal termination more visible to schedulers, automation, and operations teams.
Command procedures: CLIST and REXX return-code variables
Return-code visibility inside command procedures depends on the language.
In CLISTs, &LASTCC contains the return code from the last TSO/E command, subcommand, nested CLIST, or CLIST statement.
In TSO/E REXX, the special variable RC is normally set from the most recently issued host command.
Return Codes, ABENDs, and Completion Codes
A return code and an ABEND are related operational signals, but they are not the same thing.
A return code usually means the program reached a controlled termination point and returned a status value to its caller.
An ABEND indicates abnormal termination. It may be caused by a program check, system condition, explicit user ABEND, protection exception, missing resource, or another condition that prevented normal completion.
In batch reporting, both return codes and ABENDs influence the step result, but they are represented differently. A step can end with a condition code such as RC=8, or it can end with a system or user completion code such as S0C7, S013, U4038, or another ABEND code.
This distinction is essential for automation. Testing only return codes can miss abnormal-termination semantics; testing only ABEND status can miss controlled program failures.
Edge Cases and Architectural Curiosities
The 4095 rule: JCL completion-code limits
Although R15 is a full register, JCL step completion codes are constrained. In ordinary JCL condition-code processing, return-code values are limited to the range 0 through 4095.
When a program returns a value greater than 4095, z/OS uses the low-order portion of the value for the step condition code. IBM describes this in terms of using the rightmost three hexadecimal digits and converting them to decimal.
Example:
- Decimal
4096is hexadecimalX'1000'. - The rightmost three hexadecimal digits are
X'000'. - The reported step return code is therefore
0.
Another example:
- Decimal
5000is hexadecimalX'1388'. - The rightmost three hexadecimal digits are
X'388'. X'388'is decimal904.- The reported step return code can therefore appear as
RC=904.
The practical lesson is simple: do not design application return-code schemes that depend on values above 4095 in JCL-controlled batch.
Negative return codes
High-level languages may allow negative return values. For example, a C program can attempt to return -1.
On a two's-complement system, -1 is represented as all bits on, or X'FFFFFFFF' in a 32-bit representation. If the job-step condition-code logic takes the low-order 12 bits, the value becomes X'FFF', which is decimal 4095.
So a negative source-level return value can appear in JCL as a large positive condition code. This is one reason z/OS batch programs should use a deliberately documented, non-negative return-code range.
R15: entry-point address on the way in, return code on the way out
R15 can play two roles in standard linkage:
- On entry, it can contain the entry-point address of the called program.
- On return, it commonly contains the return code.
An assembler program that fails to set R15 before returning may therefore return an unintended value. Depending on the execution environment, that value may be interpreted as a return code and then constrained by JCL completion-code rules.
The resulting symptom can be a strange or apparently arbitrary step return code.
Language Environment and source-level return codes
Modern COBOL, PL/I, C, and C++ programs on z/OS commonly run under Language Environment (LE). LE establishes a runtime environment, manages conditions, and participates in termination processing.
A COBOL program, for example, can set the RETURN-CODE special register. A C program can return a value from main. But the source-level value is not always the entire story. Runtime conditions, abnormal termination, unhandled conditions, and LE termination handling can affect what the caller or operating system ultimately sees.
Treat the language-level return code as the intended program result, but verify how the runtime environment reports that result to the caller and to JCL, especially when unhandled conditions or ABENDs occur.
Avoid assuming that MOVE 0 TO RETURN-CODE or return 0; guarantees a clean batch step if the runtime encountered a serious unhandled condition.
z/OS UNIX, POSIX Status, and BPXBATCH
z/OS UNIX System Services introduces another layer of translation.
Traditional z/OS batch condition-code processing supports values up to 4095. POSIX-style process exit status is typically much smaller, commonly treated as an 8-bit value in the 0 through 255 range. Signal termination adds another convention: values of 128 and above often represent termination by signal, with the signal number derived by subtracting 128.
When a batch job runs UNIX work through BPXBATCH, the final step return code can depend on environment variables, spawn settings, allocation choices, and how the UNIX process ended.
Important cautions:
- A simple UNIX exit status may not always appear unchanged as the JCL return code.
- In some BPXBATCH modes, exit statuses may be multiplied by
256before being reflected in the batch step result. - The JCL
0through4095constraint can cause wraparound or unexpected values. - Signal-derived statuses can be ambiguous after translation.
For example, a UNIX process that exits with status 3 might be seen differently depending on BPXBATCH execution mode and environment settings. In some documented cases, a value can be reflected as 768, because 3 * 256 = 768.
The practical lesson is that BPXBATCH return codes should be tested in the exact execution configuration used in production. Do not assume a one-to-one mapping from POSIX exit status to JCL return code in all cases.
Practical Design Guidance
For application developers:
- Use a small, documented return-code set.
- Prefer conventional values such as
0,4,8,12, and16unless the calling contract requires something else. - Avoid negative return values.
- Avoid values above
4095in JCL-controlled batch. - Document whether return codes indicate warnings, recoverable errors, severe errors, or terminal failures.
For JCL authors:
- Prefer
IF/THEN/ELSE/ENDIFover complexCONDexpressions when readability matters. - Remember that
CONDis skip logic: if the expression is true, the step is bypassed. - Test both return-code and ABEND outcomes.
- Be cautious when running multiple TSO/E commands under one
IKJEFT01step, because later commands can affect the final reported return code. - Use
IKJEFT1AorIKJEFT1Bwhen their termination semantics better match the operational requirement.
For operations and automation teams:
- Do not treat all non-zero return codes equally.
- Do not treat
RC=0as the only possible sign of success if logs contain application-level failures. - Distinguish controlled return-code failure from ABEND failure.
- For BPXBATCH and USS workloads, validate the exact return-code mapping in the deployed environment.
8. Summary
The core contract is this:
- R15 commonly carries the program return code in standard z/OS linkage.
- JCL consumes step completion information to control downstream execution.
- The familiar
0,4,8,12,16pattern is a useful convention, not a universal rule. - TMP entry points such as
IKJEFT01,IKJEFT1A, andIKJEFT1Bdiffer materially in how they handle non-zero return codes and ABENDs. - Return codes and ABENDs are different signals and must both be considered in production control.
- Large, negative, LE-mediated, and USS/BPXBATCH-derived return codes can surprise batch designers unless explicitly tested.
A well-designed z/OS batch environment does not merely check whether a number is zero. It defines what each return code means, chooses the right execution wrapper, and ensures that JCL, schedulers, operators, and application teams all interpret the signal consistently.
Useful documentation
- IBM, z/OS MVS Programming: Assembler Services Guide — standard linkage conventions, register usage, and return conventions.
https://www.ibm.com/docs/en/zos/2.5.0?topic=program-registers
- IBM, z/OS DFSMS Using Data Sets / OPEN return codes — example of component-specific return codes using
0,4,8,12, and16.
https://www.ibm.com/docs/SSLTBW_3.1.0/com.ibm.zos.v3r1.idad500/x1cb.htm
- IBM, z/OS MVS JCL Reference and JCL User's Guide —
CONDprocessing and structured conditional execution.
https://www.ibm.com/docs/en/zos/3.1.0?topic=reference-jcl
- IBM, z/OS TSO/E Customization — Terminal Monitor Program behavior and
IKJEFT01,IKJEFT1A,IKJEFT1Breturn-code and ABEND handling.
https://www.ibm.com/docs/SSLTBW_3.1.0/pdf/ikjb400_v3r1.pdf
- IBM, z/OS TSO/E CLISTs —
&LASTCCbehavior in CLIST processing.
https://www.ibm.com/docs/en/zos/2.5.0?topic=codes-lastcc
- IBM, z/OS TSO/E REXX Reference — REXX
RCspecial variable and host command return codes.
https://www.ibm.com/docs/SSLTBW_3.2.0/pdf/ikjc300_v3r2.pdf
- IBM, z/OS TSO/E REXX Reference / IRXJCL return codes — documented use of the rightmost three hexadecimal digits for return-code values outside the JCL range.
https://www.ibm.com/docs/en/zos/2.5.0?topic=ir-return-codes
- IBM, Enterprise COBOL for z/OS Language Reference —
RETURN-CODEspecial register.
https://www.ibm.com/docs/en/cobol-zos/6.4.0?topic=registers-return-code
- IBM, z/OS Language Environment Programming Guide — LE condition and termination handling.
https://www.ibm.com/docs/en/zos/3.1.0?topic=zos-language-environment-programming-guide
- IBM, z/OS UNIX System Services User's Guide / BPXBATCH — BPXBATCH return-code behavior and POSIX status translation.
https://www.ibm.com/docs/en/zos/3.2.0?topic=environments-bpxbatch