docs.intersystems.com
Home  /  Application Development: Core Topics  /  Using ObjectScript  /  Error Processing


Using ObjectScript
Error Processing
[Back]  [Next] 
InterSystems: The power behind what matters   
Search:  


Managing the behavior of InterSystems IRIS Data Platform™ when an error occurs is called error processing or error handling. Error processing performs one or more of the following operations:
InterSystems IRIS supports three types of error processing, which can be used simultaneously. These are:
Important:
The preferred mechanism for ObjectScript error handling is the TRY-CATCH mechanism. The $ZTRAP mechanism is provided for a more traditional style of error handling.
The TRY-CATCH Mechanism
InterSystems IRIS supports a TRY-CATCH mechanism for handling errors. With this mechanism, you can establish delimited blocks of code, each called a TRY block; if an error occurs during a TRY block, control passes to the TRY block’s associated CATCH block, which contains code for handling the exception. A TRY block can also include THROW commands; each of these commands explicitly issues an exception from within a TRY block and transfers execution to a CATCH block.
To use this mechanism in its most basic form, include a TRY block within ObjectScript code. If an exception occurs within this block, the code within the associated CATCH block is then executed. The form of a TRY-CATCH block is:
 TRY {
      protected statements
 } CATCH [ErrorHandle] {
      error statements
 }
 further statements
where:
Depending on events during execution of the protected statements, one of the following events occurs:
Using THROW with TRY-CATCH
InterSystems IRIS issues an implicit exception when a runtime error occurs. To issue an explicit exception, the THROW command is available. The THROW command transfers execution from the TRY block to the CATCH exception handler. The THROW command has a syntax of:
THROW expression
where expression is an instance of a class that inherits from the %Exception.AbstractException class, which InterSystems IRIS provides for exception handling. For more information on %Exception.AbstractException, see the following section.
The form of the TRY/CATCH block with a THROW is:
 TRY {
      protected statements
      THROW expression
      protected statements
 }
 CATCH exception {
      error statements
 }
 further statements
where the THROW command explicitly issues an exception. The other elements of the TRY-CATCH block are as described in the previous section.
The effects of THROW depends on where the throw occurs and the argument of THROW:
If control passes into a CATCH block because of a THROW with an argument, the ErrorHandle contains the value from the argument. If control passes into a CATCH block because of a system error, the ErrorHandle is a %Exception.SystemException object. If no ErrorHandle is specified, there is no indication of why control has passed into the CATCH block.
For example, suppose there is code to divide two numbers:
div(num,div) public {
 TRY {
  SET ans=num/div
 } CATCH errobj {
  IF errobj.Name="<DIVIDE>" { SET ans=0 }
  ELSE { THROW errobj }
 }
 QUIT ans
}
If a divide-by-zero error happens, the code is specifically designed to return zero as the result. For any other error, the THROW sends the error on up the stack to the next error handler.
Using $$$ThrowOnError and $$$ThrowStatus Macros
InterSystems IRIS provides macros for use with exception handling. When invoked, these macros throw an exception object to the CATCH block.
The following example invokes the $$$ThrowOnError() macro when an error status is returned by the %Prepare() method:
  #Include %occStatus
  ZNSPACE "SAMPLES"
  TRY {
    SET myquery = "SELECT TOP 5 Name,Hipness,DOB FROM Sample.Person"
    SET tStatement = ##class(%SQL.Statement).%New()
    SET status = tStatement.%Prepare(myquery)
    $$$ThrowOnError(status)
    WRITE "%Prepare succeeded",!
    RETURN
  }
  CATCH sc {
    WRITE "In Catch block",!
    WRITE "error code: ",sc.Code,!
    WRITE "error location: ",sc.Location,!
    WRITE "error data:",$LISTGET(sc.Data,2),!
  RETURN
  }
The following example invokes $$$ThrowStatus after testing the value of the error status returned by the %Prepare() method:
  #Include %occStatus
  ZNSPACE "SAMPLES"
  TRY {
    SET myquery = "SELECT TOP 5 Name,Hipness,DOB FROM Sample.Person"
    SET tStatement = ##class(%SQL.Statement).%New()
    SET status = tStatement.%Prepare(myquery)
    IF ($System.Status.IsError(status)) {
      WRITE "%Prepare failed",!
      $$$ThrowStatus(status) }
    ELSE {WRITE "%Prepare succeeded",!
      RETURN }
  }
  CATCH sc {
    WRITE "In Catch block",!
    WRITE "error code: ",sc.Code,!
    WRITE "error location: ",sc.Location,!
    WRITE "error data:",$LISTGET(sc.Data,2),!
  RETURN
  }
These system-supplied macros are further described in the “ObjectScript Macros and the Macro Preprocessor” chapter of this book.
Using the %Exception.SystemException and %Exception.AbstractException Classes
InterSystems IRIS provides the %Exception.SystemException and %Exception.AbstractException classes for use with exception handling. %Exception.SystemException inherits from the %Exception.AbstractException class and is used for system errors. For custom errors, create a class that inherits from %Exception.AbstractException. %Exception.AbstractException contains properties such as the name of the error and the location at which it occurred.
When a system error is caught within a TRY block, the system creates a new instance of the %Exception.SystemException class and places error information in that instance. When throwing a custom exception, the application programmer is responsible for populating the object with error information.
An exception object has the following properties:
Other Considerations with TRY-CATCH
The following describe conditions that may arise when using a TRY-CATCH block.
QUIT within a TRY-CATCH Block
A QUIT command within a TRY or CATCH block passes control out of the block to the next statement after the TRY-CATCH as a whole.
TRY-CATCH and the Execution Stack
The TRY block does not introduce a new level in the execution stack. This means that it is not a scope boundary for NEW commands. The error statements execute at the same level as that of the error. This can result in unexpected results if there are DO commands within the protected statements and the DO target is also within the protected statements. In such cases, the $ESTACK special variable can provide information about the relative execution levels.
Using TRY-CATCH with Traditional Error Processing
TRY-CATCH error processing is compatible with $ZTRAP error traps used at different levels in the execution stack. The exception is that $ZTRAP may not be used within the protected statements of a TRY clause. User-defined errors with a THROW are limited to TRY-CATCH only. User-defined errors with the ZTRAP command may be used with any type of error processing.
%Status Error Processing
Many of the methods in the InterSystems IRIS class library return success or failure information via the %Status data type. For example, the %Save() method, used to save an instance of a %Persistent object, returns a %Status value indicating whether or not the object was saved.
You can use %SYSTEM.Status class methods to inspect and manipulate %Status values.
InterSystems IRIS provides several options for displaying (writing) the %Status encoded string in different formats. For further details, refer to Display (Write) Commands in the “Commands” chapter of this manual.
In the following example, the %Prepare fails because of an error in the myquery text: “ZOP” should be “TOP”. This error is detected by the IsError() method, and other %SYSTEM.Status methods display the error code and text:
  ZNSPACE "SAMPLES"
  SET myquery = "SELECT ZOP 5 Name,DOB FROM Sample.Person"
  SET tStatement = ##class(%SQL.Statement).%New()
  SET status = tStatement.%Prepare(myquery)
  IF ($System.Status.IsError(status)) {
      WRITE "%Prepare failed",!
      DO StatusError() }
  ELSE {WRITE "%Prepare succeeded",!
        RETURN }
StatusError()
  WRITE "Error #",$System.Status.GetErrorCodes(status),!
  WRITE $System.Status.GetOneStatusText(status,1),!
  WRITE "end of error display"
  QUIT
The following example is the same as the previous, except that the status error is detected by the $$$ISERR() macro of the %occStatus include file. $$$ISERR() (and its inverse, $$$ISOK()) checks whether or not %Status=1. The error code is returned by the $$$GETERRORCODE() macro:
#Include %occStatus
  ZNSPACE "SAMPLES"
  SET myquery = "SELECT ZOP 5 Name,DOB FROM Sample.Person"
  SET tStatement = ##class(%SQL.Statement).%New()
  SET status = tStatement.%Prepare(myquery)
  IF $$$ISERR(status) {
      WRITE "%Prepare failed",!
      DO StatusError() }
  ELSE {WRITE "%Prepare succeeded",!
        RETURN}
StatusError()
  WRITE "Error #",$$$GETERRORCODE(status),!
  WRITE $System.Status.GetOneStatusText(status,1),!
  WRITE "end of error display"
  QUIT
These system-supplied macros are further described in the “ObjectScript Macros and the Macro Preprocessor” chapter of this book.
Some methods, such as %New(), generate, but do not return a %Status. %New() either returns an oref to an instance of the class upon success, or the null string upon failure. You can retrieve the status value for methods of this type by accessing the %objlasterror system variable, as shown in the following example.
  SET session = ##class(%CSP.Session).%New()
  IF session="" {
      WRITE "session oref not created",!
      WRITE "%New error is ",!,$System.Status.GetErrorText(%objlasterror),! }
  ELSE {WRITE "session oref is ",session,! }
For more information, refer to the %SYSTEM.Status class.
Creating %Status Errors
You can invoke system-defined %Status errors from your own methods by using the Error() method. You specify the error number that corresponds to the error message you wish to return.
  WRITE "Here my method generates an error",!
  SET status = $System.Status.Error(20)
  WRITE $System.Status.GetErrorText(status),!
You can include %1, %2, and %3 parameters in the returned error message, as shown in the following example:
  WRITE "Here my method generates an error",!
  SET status = $System.Status.Error(214,"3","^fred","BedrockCode")
  WRITE $System.Status.GetErrorText(status),!
You can localize the error message to display in your preferred language.
  SET status = $System.Status.Error(30)
  WRITE "In English:",!
  WRITE $System.Status.GetOneStatusText(status,1,"en"),!
  WRITE "In French:",!
  WRITE $System.Status.GetOneStatusText(status,1,"fr"),!
For a list of error codes and messages (in English), refer to the General Error Messages chapter of the InterSystems IRIS Error Reference.
You can use the generic error codes 83 and 5001 to specify a custom message that does not correspond to any of the general error messages.
You can use the AppendStatus() method to create a list of multiple error messages. Then you can use GetOneErrorText() or GetOneStatusText() to retrieve individual error messages by their position in this list:
CreateCustomErrors
  SET st1 = $System.Status.Error(83,"my unique error")
  SET st2 = $System.Status.Error(5001,"my unique error")
  SET allstatus = $System.Status.AppendStatus(st1,st2)
DisplayErrors
  WRITE "All together:",!
  WRITE $System.Status.GetErrorText(allstatus),!!
  WRITE "One by one",!
  WRITE "First error format:",!
  WRITE $System.Status.GetOneStatusText(allstatus,1),!
  WRITE "Second error format:",!
  WRITE $System.Status.GetOneStatusText(allstatus,2),!
%SYSTEM.Error
The %SYSTEM.Error class is a generic error object. It can be created from a %Status error, from an exception object, a $ZERROR error, or an SQLCODE error. You can use %SYSTEM.Error class methods to convert a %Status to an exception, or to convert an exception to a %Status.
Traditional Error Processing
This section describes various aspects of traditional error processing with InterSystems IRIS. These include:
How Traditional Error Processing Works
For traditional error processing, InterSystems IRIS provides the functionality so that your application can have an error handler. An error handler processes any error that may occur while the application is running. A special variable specifies the ObjectScript commands to be executed when an error occurs. These commands may handle the error directly or may call a routine to handle it.
To set up an error handler, the basic process is:
  1. Create one or more routines to perform error processing. Write code to perform error processing. This can be general code for the entire application or specific processing for specific error conditions. This allows you to perform customized error handling for each particular part of an application.
  2. Establish one or more error handlers within your application, each using specific appropriate error processing.
If an error occurs and no error handler has been established, the behavior depends on how the InterSystems IRIS session was started:
  1. If you signed onto InterSystems IRIS in Programmer Mode and have not set an error trap, InterSystems IRIS displays an error message on the principal device and enters Programmer Mode with the program stack intact. The programmer can later resume execution of the program.
  2. If you invoked InterSystems IRIS in Application Mode and have not set an error trap, InterSystems IRIS displays an error message on the principal device and executes a HALT command.
Internal Error-Trapping Behavior
To get the full benefit of InterSystems IRIS error processing and the scoping issues surrounding the $ZTRAP special variable, it is helpful to understand how InterSystems IRIS transfers control from one routine to another.
InterSystems IRIS builds a data structure called a “context frame” each time any of the following occurs:
The frame is built on the call stack, one of the private data structures in the address space of your process. InterSystems IRIS stores the following elements in the frame for a routine:
When routine A calls routine B with DO ^B, InterSystems IRIS builds a DO frame on the call stack to preserve the context of A. When routine B calls routine C, InterSystems IRIS adds a DO frame to the call stack to preserve the context of B, and so forth.
Frames on a Call Stack
If routine A in the figure above is invoked at the Programmer Mode prompt using the DO command, then an extra DO frame, not described in the figure, exists at the base of the call stack.
Current Context Level
You can use the following to return information about the current context level:
The $STACK Special Variable
The $STACK special variable contains the number of frames currently saved on the call stack for your process. The $STACK value is essentially the context level number (zero based) of the currently executing context. Therefore, when an image is started, but before any commands are processed, the value of $STACK is 0.
See the $STACK special variable in the ObjectScript Reference for details.
The $ESTACK Special Variable
The $ESTACK special variable is similar to the $STACK special variable, but is more useful in error handling because you can reset it to 0 (and save its previous value) with the NEW command. Thus, a process can reset $ESTACK in a particular context to mark it as a $ESTACK level 0 context. Later, if an error occurs, error handlers can test the value of $ESTACK to unwind the call stack back to that context.
See the $ESTACK special variable in the ObjectScript Reference for details.
The $STACK Function
The $STACK function returns information about the current context and contexts that have been saved on the call stack. For each context, the $STACK function provides the following information:
When an error occurs, all context information is immediately saved on your process error stack. The context information is then accessible by the $STACK function until the value of $ECODE is cleared by an error handler. In other words, while the value of $ECODE is non-null, the $STACK function returns information about a context saved on the error stack rather than an active context at the same specified context level.
See the $STACK function in the ObjectScript Reference for details.
When an error occurs and an error stack already exists, InterSystems IRIS records information about the new error at the context level where the error occurred, unless information about another error already exists at that context level on the error stack. In this case, the information is placed at the next level on the error stack (regardless of the information that may already be recorded there).
Therefore, depending on the context level of the new error, the error stack may extend (one or more context levels added) or information at an existing error stack context level may be overwritten to accommodate information about the new error.
Keep in mind that you clear your process error stack by clearing the $ECODE special variable.
Error Codes
When an error occurs, InterSystems IRIS sets the $ZERROR and $ECODE special variables to a value describing the error.
$ZERROR Value
InterSystems IRIS sets $ZERROR to a string containing:
The AsSystemError() method of the %Exception.SystemException class returns the same values in the same format as $ZERROR.
The following examples show the type of messages to which $ZERROR is set when InterSystems IRIS encounters an error. In the following example, the undefined local variable abc is invoked at line offset 2 from label PrintResult of routine MyTest. $ZERROR contains:
<UNDEFINED>PrintResult+2^MyTest *abc
The following error occurred when a non-existent class is invoked at line offset 3:
<CLASS DOES NOT EXIST>PrintResult+3^MyTest *%SYSTEM.XXQL
The following error occurred when a non-existent method of an existing class is invoked at line offset 4:
<METHOD DOES NOT EXIST>PrintResult+4^MyTest *BadMethod,%SYSTEM.SQL
You can also explicitly set the special variable $ZERROR as any string up to 128 characters; for example:
 SET $ZERROR="Any String"
The $ZERROR special variable retains its value until an error occurs or until you set it to a new value.
See the $ZERROR special variable in the ObjectScript Reference for details. For further information on handling $ZERROR errors, refer to the %SYSTEM.Error class methods in the InterSystems Class Reference.
$ECODE Value
When an error occurs, InterSystems IRIS sets $ECODE to the value of a comma-surrounded string containing the ANSI Standard error code that corresponds to the error. For example, when you make a reference to an undefined global variable, InterSystems IRIS sets $ECODE set to the following string:
,M7,
If the error has no corresponding ANSI Standard error code, InterSystems IRIS sets $ECODE to the value of a comma-surrounded string containing the InterSystems IRIS error code preceded by the letter Z. For example, if a process has exhausted its symbol table space, InterSystems IRIS places the error code <STORE> in the $ZERROR special variable and sets $ECODE to this string:
,ZSTORE,
After an error occurs, your error handlers can test for specific error codes by examining the value of the $ZERROR special variable or the $ECODE special variable.
Note:
Error handlers should examine $ZERROR rather than $ECODE special variable for specific errors.
See the $ECODE special variable in the ObjectScript Reference for details.
Handling Errors with $ZTRAP
To handle errors with $ZTRAP, you set the $ZTRAP special variable to a location, specified as a quoted string. You set the $ZTRAP special variable to an entry reference that specifies the location to which control is to be transferred when an error occurs. You then write $ZTRAP code at that location.
Setting $ZTRAP in a Procedure
Within a procedure, you can only set the $ZTRAP special variable to a line label (private label) within that procedure.
When displaying the $ZTRAP value, InterSystems IRIS does not return the name of the private label. Instead, it returns the offset from the top of the procedure where that private label is located.
For further details see the $ZTRAP special variable in the ObjectScript Reference.
Setting $ZTRAP in a Routine
Within a routine, you can set the $ZTRAP special variable to a label in the current routine, to an external routine, or to a label within an external routine. The following example establishes LogErr^ErrRou as the error handler. When an error occurs, InterSystems IRIS executes the code found at the LogErr label within the ^ErrRou routine:
  SET $ZTRAP="LogErr^ErrRou"
When displaying the $ZTRAP value, InterSystems IRIS displays the label name and (when appropriate) the routine name.
A label name must be unique within its first 31 characters. Label names and routine names are case-sensitive.
Within a routine, $ZTRAP has three forms:
For further details see the $ZTRAP special variable in the ObjectScript Reference.
Writing $ZTRAP Code
The location that $ZTRAP points to can perform a variety of operations to display, log, and/or correct an error. Regardless of what error handling operations you wish to perform, the $ZTRAP code should begin by performing two tasks:
The following example shows these essential $ZTRAP code statements:
MyErrHandler
  SET $ZTRAP=""
  SET err=$ZERROR
  /* error handling code
     using err as the error
     to be handled */
Using $ZTRAP
Each routine in an application can establish its own $ZTRAP error handler by setting $ZTRAP. When an error trap occurs, InterSystems IRIS takes the following steps:
  1. Sets the special variable $ZERROR to an error message.
  2. Resets the program stack to the state it was in when the error trap was set (when the SET $ZTRAP= was executed). In other words, the system removes all entries on the stack until it reaches the point at which the error trap was set. (The program stack is not reset if $ZTRAP was set to a string beginning with an asterisk (*).)
  3. Resumes the program at the location specified by the value of $ZTRAP. The value of $ZTRAP remains the same.
    Note:
    You can explicitly set the variable $ZERROR as any string up to 128 characters. The $ZERROR special variable retains its value until an error occurs or until you set it to a new value. Usually you would set $ZERROR only to a null string, but you can set $ZERROR to a value.
Unstacking NEW Commands With Error Traps
When an error trap occurs and the program stack entries are removed, InterSystems IRIS also removes all stacked NEW commands back to the subroutine level containing the SET $ZTRAP=. However, all NEW commands executed at that subroutine level remain, regardless of whether they were added to the stack before or after $ZTRAP was set.
For example:
Main
  SET A=1,B=2,C=3,D=4,E=5,F=6
  NEW A,B
  SET $ZTRAP="ErrSub"
  NEW C,D
  DO Sub1
  RETURN
Sub1()
  NEW E,F
  WRITE 6/0    // Error: division by zero
  RETURN
ErrSub()
  WRITE !,"Error is: ",$ZERROR
  WRITE
  RETURN
When the error in Sub1 activates the error trap, the former values of E and F stacked in Sub1 are removed, but A, B, C, and D remain stacked.
$ZTRAP Flow of Control Options
After a $ZTRAP error handler has been invoked to handle an error and has performed any cleanup or error logging operations, the error handler has three flow control options:
Continuing the Application
After a $ZTRAP error handler has handled an error, you can continue the application by issuing a GOTO. You do not have to clear the values of the $ZERROR or $ECODE special variables to continue normal application processing. However, you should clear $ZTRAP (by setting it to the empty string) to avoid a possible infinite error handling loop if another error occurs. See Handling Errors in an Error Handler for more information.
After completing error processing, your $ZTRAP error handler can use the GOTO command to transfer control to a predetermined restart or continuation point in your application to resume normal application processing.
When an error handler has handled an error, the $ZERROR special variable is set to a value. This value is not necessarily cleared when the error handler completes. The $ZERROR value is overwritten when the next error occurs that invokes an error handler. For this reason, the $ZERROR value should only be accessed within the context of an error handler. Accessing $ZERROR in any other context does not produce reliable results.
Passing Control to Another Error Handler
If the error condition cannot be corrected by a $ZTRAP error handler, you can use a special form of the ZTRAP command to transfer control to another error handler. The command ZTRAP $ZERROR re-signals the error condition and causes InterSystems IRIS to unwind the call stack to the next call stack level with an error handler. After InterSystems IRIS has unwound the call stack to the level of the next error handler, processing continues in that error handler. The next error handler may have been set by a $ZTRAP.
The following figure shows the flow of control in $ZTRAP error handling routines.
$ZTRAP Error Handlers
Handling Errors in a $ZTRAP Error Handler
When an error occurs in an error handler, the flow of execution depends on the type of error handler that is currently executing.
If the new error occurs in a $ZTRAP error handler, InterSystems IRIS passes control to the first error handler it encounters, unwinding the call stack only if necessary. Therefore, if the $ZTRAP error does not clear $ZTRAP at the current stack level and another error subsequently occurs in the error handler, the $ZTRAP handler is invoked again at the same context level, causing an infinite loop. To avoid this, Set $ZTRAP to another value at the beginning of the error handler.
Error Information in the $ZERROR and $ECODE Special Variables
If another error occurs during the handling of the original error, information about the second error replaces the information about the original error in the $ZERROR special variable. However, InterSystems IRIS appends the new information to the $ECODE special variable. Depending on the context level of the second error, InterSystems IRIS may append the new information to the process error stack as well.
If the existing value of the $ECODE special variable is non-null, InterSystems IRIS appends the code for the new error to the current $ECODE value as a new comma piece. Error codes accrue in the $ECODE special variable until either of the following occurs:
Then, the next new error code replaces the current list of error codes in $ECODE.
When an error occurs and an error stack already exists, InterSystems IRIS records information about the new error at the context level where the error occurred, unless information about another error already exists at that context level on the error stack. In this case, the information is placed at the next level on the error stack (regardless of the information that may already be recorded there).
Therefore, depending on the context level of the new error, the error stack may extend (one or more context levels added) or information at an existing error stack context level may be overwritten to accommodate information about the new error.
Keep in mind that you clear your process error stack by clearing the $ECODE special variable.
See the $ECODE and $ZERROR special variables in the ObjectScript Reference for details. For further information on handling $ZERROR errors, refer to the %SYSTEM.Error class methods in the InterSystems Class Reference.
Forcing an Error
You set the $ECODE special variable or use the ZTRAP command to cause an error to occur under controlled circumstances.
Setting $ECODE
You can set the $ECODE special variable to any non-null string to cause an error to occur. When your routine sets $ECODE to a non-null string, InterSystems IRIS sets $ECODE to the specified string and then generates an error condition. The $ZERROR special variable in this circumstance is set with the following error text:
<ECODETRAP>
Control then passes to error handlers as it does for normal application-level errors.
You can add logic to your error handlers to check for errors caused by setting $ECODE. Your error handler can check $ZERROR for an <ECODETRAP> error (for example, “$ZE["ECODETRAP"”) or your error handler can check $ECODE for a particular string value that you choose.
Creating Application-Specific Errors
Keep in mind that the ANSI Standard format for $ECODE is a comma-surrounded list of one or more error codes:
You can create your own error codes following the ANSI Standard by having the error handler set $ECODE to the appropriate error message prefixed with a “U”.
  SET $ECODE=",Upassword expired,"
Processing Errors in Programmer Mode
When you generate an error after you sign onto InterSystems IRIS in Programmer Mode with no error handler set, InterSystems IRIS takes the following steps when an error occurs in a line of code you enter:
  1. InterSystems IRIS displays an error message on the process’s principal device
  2. The process breaks at the call stack level where the error occurred
  3. The process enters Programmer Mode.
Understanding Error Message Formats
As an error message, InterSystems IRIS displays three lines:
  1. The entire line of source code in which the error occurred.
  2. Below the source code line, a caret (^) points to the command that caused the error.
  3. A line containing the contents of $ZERROR.
In the following Terminal prompt example, the second SET command has an undefined local variable error:
USER>WRITE "hello",! SET x="world" SET y=zzz WRITE x,!
hello

WRITE "hello",! SET x="world" SET y=zzz WRITE x,!
                              ^
<UNDEFINED> *zzz
USER>
In the following example, the same line of code is in a program named mytest executed from the Terminal prompt:
USER>DO ^mytest
hello

  WRITE "hello",! SET x="world" SET y=zzz WRITE x,!
                                ^
<UNDEFINED>WriteOut+2^mytest *zzz
USER 2d0>
In this case, $ZERROR indicates that the error occurred in mytest at an offset of 2 lines from the a label named WriteOut. Note that the prompt has changed, indicating we are in Programmer Mode.
Understanding the Programmer Mode Prompt
By default, the Terminal prompt specifies the current namespace. If one or more transactions are open, it also includes the $TLEVEL transaction level count. This default prompt can be configured with different contents, as described in the ZNSPACE command documentation. The following examples show the defaults:
USER>
TL1:USER>
If an error occurs during the execution of a routine, the system saves the program stack entering Programmer Mode. An extended prompt appears, such as:
USER 2d0>
This extended prompt indicates that there are two entries on the program stack, the last of which is an invoking of DO (as indicated by the “d”). Note that this error placed two entries on the program stack. The next DO execution error would result in the prompt:
USER 4d0>
For a more detailed explanation, refer to Understanding the Programmer Mode Prompt Information in the “Command-line Routine Debugging” chapter.
Recovering from the Error
You can then take any of the following steps:
Any of these steps can even cause additional errors.
After you have taken these steps, your most likely course is to either resume execution or to delete all or part of the program stack.
Resuming Execution at the Next Sequential Command
You can resume execution at the next command after the command that caused the error by entering an argumentless GOTO in Programmer Mode:
USER>DO ^mytest
hello

  WRITE "hello",! SET x="world" SET y=zzz WRITE x,!
                                ^
<UNDEFINED>WriteOut+2^mytest *zzz
USER 2d0>GOTO
world

USER>
Resuming Execution at Another Line
You can resume execution at another line by issuing a GOTO with a label argument in Programmer Mode:
USER 2d0>GOTO ErrSect
Deleting the Program Stack
You can delete the entire program stack by issuing an argumentless QUIT command in Programmer Mode:
USER 4d0>QUIT
USER>
Deleting Part of the Program Stack
You can issue QUIT n with an integer argument to delete the last (or last several) program stack entry:
USER 8d0>QUIT 1
 
USER 7E0>QUIT 3
 
USER 4d0>QUIT 1
 
USER 3E0>QUIT 1
 
USER 2d0>QUIT 1
 
USER 1S0>QUIT 1
 
USER>
Note that in this example because the program error created two program stack entries, you must be on a “d” stack entry to resume execution by issuing a GOTO. Depending on what else has occurred, a “d” stack entry may be even-numbered (USER 2d0>) or odd-numbered (USER 3d0>).
By using NEW $ESTACK, you can quit to a specified program stack level:
USER 4d0>NEW $ESTACK

USER 5E1>
/* more errors create more stack frames */

USER 11d7>QUIT $ESTACK
 
USER 4d0>
Note that the NEW $ESTACK command adds one entry to the program stack.