Error Handling in Subprograms

Never Abort from a Subprogram

A subprogram has no business aborting. If it encounters a fatal error condition, it should return some kind of error code. Then the calling program has a chance to issue error messages, close its files, and otherwise clean itself up before aborting.

This approach requires more care than usual. In a top-level program, you can abort pretty much whenever you want. When one paragraph PERFORMs another, it won't even regain control if the second paragraph aborts. In a subprogram, however, the first paragraph may need to check whether the second one encountered a fatal error. The error may have to percolate through several layers of code before it reaches the calling program.

After a Fatal Error, Stop

By definition, once a fatal error occurs, you can no longer do any useful work.

If a subprogram reports a fatal error to the calling program, the calling program should abort. But maybe it won't. Maybe it will call the subprogram again.

The subprogram must protect itself from such improper calls. When it detects a fatal error it should set a switch so that it can remember that a fatal error has occurred. In any subsequent call, the subprogram should check the switch, notice the previous error, and return immediately without doing anything.

There are exceptions. If there is a routine for returning an error message, an error obviously should not disable it. It may also make sense to honor a request to shut down the module (close files, release memory, and so forth).

Issuing Error Messages

When a subprogram encounters an error, some module needs to issue an error message. The simplest and most obvious approach is for the subprogram to issue the message itself, by whatever means are customary within the application.

However, this approach limits the subprogram to a specific way of issuing messages. Techniques designed for batch programs may not work for IMS transactions or CICS programs. Different applications follow different conventions.

In order to be reusable in other contexts, a subprogram should not issue error messages on its own. It should pass information about the error back up to the calling program, and let it be responsible for issuing the message.

This approach calls for some extra machinery to pass the information upward. It can be awkward when the information must pass up through several layers of software. If a module is inherently restricted to a particular application and a particular environment, it might as well avoid these problems by issuing its own messages.

Passing Errors Upward

At a minimum, most subprograms should return a status code to the calling program. If each kind of error results in a different kind of status code, the calling program has the option of treating different errors differently.

For issuing error messages this technique is not enough, because it requires the calling program to have detailed knowledge of the meaning of each error code. In addition, a meaningful message may need to incorporate information which is not available to the calling program.

Many JOCKEY subprograms provide a separate entry point to return fifty characters of text describing the most recent error. In most cases the calling program can use this text to build an error message without knowing anything further about specific status codes.

Check Status Codes

If a subprogram returns a status code, the calling program should check the code before proceeding further. Otherwise the calling program is either: Usually the tidiest arrangement is to write a separate paragraph which calls the subprogram, checks the status code, issues any appropriate error messages, abends if necessary -- and very little else.

Avoid Status Codes Whenever Possible

Checking status codes is a good habit, but it's still a pain in the neck. Whenever possible, design a calling interface in such a way that errors are not an issue.

For example: the JK015 routines manage a collection of named variables. One entry point, JKGETENV, fetches the value of a variable whose name is specified by the calling program. It obtains the value of such variables by loading a small file into a WORKING-STORAGE table.

There may be a table overflow in loading the variables. In one possible design, JKGETENV would return a status code meaning "table overflow" or "variable not found."

Instead, JKGETENV merely reports that the variable has a value of blank spaces. There is no status code to test. As a result, JKGETENV is simpler to use than it would be if the calling program had to check a status code after every call. If a program needs to be paranoid about possible errors, it can use certain other entry points to detect them.


homeCOBOL Home [style forum]COBOL Style Forum