S002: Invalid record or block (QSAM or BSAM)
An S002 abend means QSAM or BSAM rejected a record or block while processing a sequential data set, almost always because its length doesn't fit the record format, LRECL or BLKSIZE. Message IEC036I comes with it, and its return code names the exact rule that was broken.
Other names for this code
Also written as 002, abend 002, system abend 002, ABEND S002, S002 abend, IEC036I, IEC036I 002.
What it means
Programs read and write sequential data sets through the QSAM and BSAM access methods, which are part of DFSMSdfp. Every record and every block has to fit the data set's record format (RECFM), logical record length (LRECL) and block size (BLKSIZE). When the access method finds a record or block that breaks those rules, it ends the task with system completion code 002. IBM also uses this code for some errors while a program creates a BDAM (direct) data set.
The abend always comes with message IEC036I in the job log. The message names the job, the step, the DD name and the data set, and it carries a two-digit return code. That return code is the diagnosis. Each value stands for one specific check, so look it up in the IEC036I entry in z/OS MVS System Messages, Volume 7, for your release before changing anything.
Variable-length files (RECFM=V, VB or VBS) cause most S002 abends. Each variable record starts with a 4-byte record descriptor word (RDW), and the first two bytes of the RDW hold the record length, counting the RDW itself. Each block starts with a similar block descriptor word (BDW). If a program builds a record without a correct RDW, or reads a file whose bytes aren't really laid out that way, the lengths don't add up and the access method stops the step.
Common causes
- The data set is described as variable-length (RECFM=V or VB) in the JCL or the catalog, but the data was written as fixed-length, or arrived through a file transfer that never built RDWs. The access method reads the first bytes of the data as a length.
- A program that writes a variable-length file sets the record length wrong. In assembler this is the RDW in front of the record passed to PUT or WRITE. The length is zero, larger than LRECL, or left over from an earlier record.
- The block size is too small for the longest record. For RECFM=VB, BLKSIZE has to be at least LRECL plus 4. For RECFM=U, every record is a block and can't be longer than BLKSIZE.
- A DD statement overrides RECFM, LRECL or BLKSIZE with values that don't match how the data set was really written.
- Storage holding the record or its length was overwritten before the PUT or WRITE, so the access method was handed garbage.
How to find the problem
- Find IEC036I in the job log (JESMSGLG or JESYSMSG in SDSF). Note the return code after
002-, the DD name and the data set name. - Look up that return code in the IEC036I entry for your z/OS release. It tells you whether the problem is the record length, the block length or something else, which decides where to look next.
- Compare the data set's real attributes (ISPF option 3.4, or a LISTCAT for cataloged data sets) with what the DD statement and the program specify. Attributes coded in the program's DCB or COBOL FD take priority over the DD statement, and the DD statement takes priority over the data set label.
- Look at the raw bytes of the failing record. A copy step that reads the input as
RECFM=shows whole blocks, including the BDW and RDWs that ISPF browse hides. A length field that reads as text, such as X'4040', means the file isn't really variable-length.U, BLKSIZE= 32760 - If the error keeps coming back and the program looks correct, IBM suggests a GTF trace with
DCB=DIAGNS=TRACEon the DD statement of the failing data set.
How to fix it
- Correct the DD statement so RECFM, LRECL and BLKSIZE match the data, or remove the overrides and let the data set label supply them.
- Fix the program that writes the file so every record gets the right length. In COBOL, keep the RECORD VARYING DEPENDING ON field within the record's minimum and maximum. In assembler, set the RDW before each PUT.
- If the file came from another platform, transfer it again in a way that builds proper records, or convert it to fixed-length first and copy it to variable-length with a utility such as DFSORT.
- Make the block size large enough, or leave BLKSIZE out for new DASD data sets so the system picks one.
- Delete any partly written output data set and rerun from the failed step.
IBM documentation
IBM z/OS: 002. Use the documentation for your installed release.
Related codes
Questions
What is the difference between S001 and S002?
S001 reports an I/O error and comes with message IEC020I. S002 means the access method found a record or block that breaks the format rules, and it comes with IEC036I. Both put the real reason in the return code of their message.
Why does the failing record have a length like 16448?
16448 is X'4040', which is two EBCDIC spaces read as a binary number. It means the access method is treating text as a record descriptor word, so the file isn't really variable-length or the data is out of step.
Can a program catch an S002?
An assembler program can supply a DCB ABEND exit, and the system calls it before ending the task. Most programs don't, and the lasting fix is to correct the data or the attributes.