.. http://www.lassosoft.com/Language-Guide-Error-Handling .. _error-handling: ************** Error Handling ************** Responding to errors gracefully is a hallmark of good programming. Errors in Lasso run the gamut from expected errors, such as a database search that returns no records, to syntax errors that require fixing before a page will even process. Lasso provides tools to manage errors at several different levels, which can act redundantly to ensure that no errors will be missed. Error Types =========== The following lists the types of errors that can occur in Lasso: Web Server Errors These include "file not found" errors and access violations in realms. These will be reported with standard HTTP response codes (e.g. 404 for "File Not Found"). Syntax Errors These include misspellings of type or method names, missing delimiters, and mismatched types. Lasso will return an error message rather than the processed Lasso page if it encounters a syntax error. Action Errors These include missing or misspelled database names, table names, or field names, and other problems specifying database actions. The database action cannot be performed until the error is corrected. Database Errors These are generated by the data source application and include type mismatches, missing required field values, and others. Lasso will report the returned error from the data source application without modification. Logical Errors These are problems that cause a page to process unexpectedly even though the syntax of the code is correct. These include infinite loops, missing cases, and assumptions about the size or composition of a found set. Security Violations These are not strictly errors, but are attempts to perform database actions or file accesses that are not allowed by the permissions set for the current user. Operating System Errors These are errors reported by the operating system Lasso is running on. One example of these errors is trying to perform file operations on a directory. Some errors are more serious than others. Pages will not be processed at all if they contain syntax errors or if there are operational problems that prevent Lasso Server from being accessed. Other errors are commonly encountered in the normal use of a website. Most database errors and security violations are handled by simply showing a "No Records Found" message or displaying a security dialog box to prompt the user for a username and password. The following mechanisms for handling errors can be used individually or in concert to provide comprehensive error handling: - Automatic error reporting is performed by Lasso in response to unhandled errors. - A custom error page allows the automatic error report to be replaced by a custom page. Custom error pages are usually created for each site on a server. - Error handling methods allow action and logical errors and security violations to be handled within a Lasso page. - Error handling methods allow advanced error handling to be built into Lasso pages. These techniques allow error handling routines to be built into a page without disrupting the normal processing of a page if no errors occur. Error Reporting =============== Lasso Server delivers an error report in response to an error that prevents processing of the page. This error report contains an error code, message, and stack trace which can be used to identify the cause and location of an error. The various parts of the stack can be accessed using the ``error_…`` methods. While the standard error report is great for developers, it is meaningless for visitors to your website. A custom error page can be defined to be displayed to a site visitor rather than Lasso's built-in error report. The error message displayed on a custom error page will depend on the Lasso code used on the custom page. To define a custom error page, create a file named :file:`error.lasso` and place it in the root of the web serving folder. Each distinct web serving folder on a host can have a custom error page. Custom error pages can be further fine-tuned by placing the :file:`error.lasso` file in the web serving folder's subdirectories. Lasso Server will process the first :file:`error.lasso` it encounters on the file path, starting with the current directory and continuing upward until it reaches the root of the web serving folder. If none are found, Lasso Server will use the default error report. Error Reporting Methods ----------------------- The ``error_…`` methods in Lasso allow custom errors to be reported and provide access to the most recently reported error by the code executing in the current Lasso page. This allows a developer to check for specific errors and respond, if necessary, with an error message or with code to correct the error. Lasso maintains a single error code and error message, which is set by any method that reports an error. The error code and error message should be checked immediately after a method that may report an error. If any intervening methods or expressions report errors, then the original error code and error message will be lost. Custom errors can be created using the `error_setErrorMessage` and `error_setErrorCode` methods. Once set, the `error_currentError` method or `error_code` and `error_msg` methods will return the custom error code and message. A developer can use these methods to incorporate both built-in and custom error codes into the error recovery mechanisms for a site. .. method:: error_currentError(-errorCode= ?) Returns the current error message. The optional ``-errorCode`` parameter causes the current error code to be returned instead. .. method:: error_code() Returns the current error code. .. method:: error_msg() Returns the current error message. .. method:: error_obj() Returns the current error name from the Lasso variable ``$_err_obj``, or "null" if no error object is present. .. method:: error_push() Pushes the current error condition onto a stack and resets the current error code and error message. .. method:: error_pop() Restores the most recent error condition stored using `error_push`. .. method:: error_reset() Resets the current error code and error message. .. method:: error_setErrorCode(code) Sets the current error code to a custom value. .. method:: error_setErrorMessage(msg) Sets the current error message to a custom value. .. method:: error_stack() Returns the stack trace for the current error. Display the Current Error ^^^^^^^^^^^^^^^^^^^^^^^^^ The following code will display a short error message using the `error_msg` method and the `error_code` method. If the code on the page is executing normally and there is no current error to report then the code will return the result shown below:: 'The current error is ' + error_code + ': ' + error_msg // => The current error is 0: No Error Alternatively, the `error_currentError` method could be used to create the same message with the following code:: 'The current error is ' + error_currentError(-errorCode) + ': ' + error_currentError // => The current error is 0: No Error Set the Current Error ^^^^^^^^^^^^^^^^^^^^^ The current error code and message can be set using the `error_setErrorCode` and `error_setErrorMessage` methods. These methods will not affect the execution of the current Lasso page, but will simply set the current error so it will be returned by the `error_currentError` method or `error_code` and `error_msg` methods. In the following example, the error message is set to "A custom error occurred" and the error code is set to "-1":: error_setErrorMessage('A custom error occurred') error_setErrorCode(-1) The `error_currentError` method now reports this custom error when it is called later in the page, unless any intervening code changed the error message again:: 'The current error is ' + error_code + ': ' + error_msg // => The current error is -1: A custom error occurred The current error code and message can also be set using the `error_code` and `error_msg` methods:: error_msg = 'A custom error occurred' error_code = -1 Store and Restore the Current Error ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following code uses the `error_push` and `error_pop` methods to store the current error code and message before the `protect` block is executed. This allows the `protect` block to execute without any previous error on the page bleeding into it and mistakenly triggering the `handle_failure` block. Then the error code and message are restored at the end of the block. :: error_push // Push error onto stack protect => { // Protect from failure handle_failure => { // Handle any errors generated within the protect block } // ... } error_pop // Retrieve error from stack The `error_push` and `error_pop` methods can also be used to prevent custom methods from modifying the current error condition, while still using error-handling code within the method. The following code stores the current error code and message at the beginning of the custom method definition. The error code and message are restored just before the custom method returns a value. :: define myMethod() => { // Push current error onto stack error_push // ... code that may generate an error ... // Retrieve error from stack error_pop return 'myValue' } Reset the Current Error ^^^^^^^^^^^^^^^^^^^^^^^ The following code demonstrates how to use the `error_reset` method to reset the error message to "No error" and the error code to "0":: error_code = -1 error_msg = 'Too slow' error_code + ': ' + error_msg // => -1: Too slow error_reset error_code + ': ' + error_msg // => 0: No error Lasso Errors ------------ The table below lists Lasso's standard error codes and values. .. tabularcolumns:: lL .. _error-handling-lasso: .. table:: Lasso Error Codes and Messages =============================== ============================================= Error Method Value =============================== ============================================= ``error_code_noerror`` 0 ``error_msg_noerror`` No error ``error_code_fileNotFound`` 404 ``error_msg_fileNotFound`` File not found ``error_code_runtimeAssertion`` -9945 ``error_msg_runtimeAssertion`` Runtime assertion ``error_code_aborted`` -9946 ``error_msg_aborted`` General Abort ``error_code_methodNotFound`` -9948 ``error_msg_methodNotFound`` Method not found ``error_code_divideByZero`` -9950 ``error_msg_divideByZero`` Divide by Zero ``error_code_invalidParameter`` -9956 ``error_msg_invalidParameter`` Invalid parameter ``error_code_networkError`` -9965 ``error_msg_networkError`` Network error ``error_code_resNotFound`` -9967 ``error_msg_resNotFound`` Resource not found =============================== ============================================= Error Handling ============== Lasso includes powerful error handling methods that allow areas of a page to be protected and errors to be handled. Error-specific handlers are called if any errors occur in a protected area of a page. These methods allow comprehensive error handling to be built into a page without disturbing the code of the page with many conditionals and special cases. Error Handling Methods ---------------------- .. method:: fail(msg::string) .. method: fail(code::integer, msg::string) .. method:: fail(code::integer, msg::string, stack::string= ?) Halts execution and generates the specified error. Can be called with just an error message, an error code and an error message, or an error code, message, and stack trace. .. method:: fail_if(cond, msg::string) .. method:: fail_if(cond, code::integer, msg::string) Conditionally halts execution and generates the specified error if the specified condition evaluates to "true". Takes two or three parameters: a conditional expression, an integer error code, and a string error message or just the conditional expression and the error message. .. method: handle() .. method:: handle(cond= ?) Conditionally executes a given capture block after the code in the current capture block or Lasso page has completed or a `fail` method is called. May take a conditional expression as a parameter that limits executing the capture block to when the conditional statement evaluates to "true". If an error occurs in the Lasso code before the handle block is defined, then the handle's capture block will not be executed. .. method: handle_failure() .. method:: handle_failure(cond= ?) Functions the same as `handle` except that the contents are executed only if an error was reported in the surrounding capture block or Lasso page. .. method:: protect() Protects a portion of a page. If code inside the given capture block throws an error or a `fail` method is executed inside the capture block, then the error is not allowed to propagate outside the protected capture block. This means that a `fail` will only halt the execution of the rest of the code in the `protect` capture, and execution will resume starting with the code following that capture. .. method:: abort() Sets the current error code to ``error_code_aborted`` and stops Lasso from continuing execution. This *cannot* be stopped with `protect`. handle and handle_failure ------------------------- The `handle` method is used to specify a block of code that will be executed after the current code segment is completed. The `handle` method can take a single parameter that is a conditional expression (defaults to "true"). If the conditional expression evaluates as "true", then the code in the given capture block is executed. All `handle` and `handle_failure` methods are processed sequentially, giving each a chance to be executed in the order they were specified and allowing for execution of multiple `handle` blocks. Therefore, it is necessary to define them before logic that could halt execution. Any `handle` methods that are defined after a script failure will not be executed. It is generally good practice to place `handle` and `handle_failure` methods at the start of the parent capture block, most commonly a `protect` capture block. (This is a change from previous versions of Lasso and increases the reliability of executing fault-condition fallbacks.) The `handle` methods will not be executed if a syntax error occurs while Lasso is parsing a page. When Lasso encounters a syntax error it returns an error page instead of processing the code on the page. The `handle` methods will be executed if a logical error occurs while Lasso is processing a page. However, the returned result will be an error message rather than the output of the page. Code within the `handle` capture block can redirect the user to another page using `redirect_url` or can replace the contents of the page being served. There are two ways to use `handle` methods within a Lasso page: #. When used on their own in a Lasso page, the code inside the `handle` methods will be conditionally executed after all the rest of the code in the Lasso page has completed. The `handle` methods can be used to provide post-processing code for a Lasso page. #. When used within any Lasso capture block, the code inside the `handle` methods will be conditionally executed after the capture block is executed. The `handle` methods will most commonly be used within a `protect` block to provide error handling. fail and fail_if ---------------- The `fail` method allows an error to be triggered from within Lasso code. Use of the `fail` method immediately halts execution of the current page and starts execution of any registered `handle` method contained within. The `fail` method can be used in the following ways: - To report an unrecoverable error. Just as Lasso automatically halts execution of a Lasso page when a syntax error or internal error is encountered, Lasso code can use the `fail` method to report an error that cannot be recovered from:: fail(-1, 'An unrecoverable error occurred') - To trigger immediate execution of the page's `handle` methods. If an error is handled by one of the `handle` methods specified in the Lasso page (outside of any other capture blocks), then the code within the `handle` capture block will be executed. The `handle` block can recover from the error and allow execution to continue by using the `error_reset` method. - To trigger immediate execution of a `protect` capture block's `handle` block, which is described in the next section. The `fail_if` method allows conditional execution of a `fail` without using a full if/else conditional. The first parameter to `fail_if` is a conditional expression. The last two parameters are the same integer error code and string error message as in the `fail` method. In the following example the `fail_if` method is only executed if the variable "x" does not equal "0":: fail_if(#x != 0, 100, "Value does not equal 0.") protect ------- The `protect` method is used to catch any errors that occur within the code surrounded by the capture block. They create a protected environment from which errors cannot propagate to the page itself. Even if Lasso reports an internal error it will be caught by the `protect` method, allowing the rest of the page to execute successfully. Any `fail` or `fail_if` methods called within `protect` capture blocks will halt execution only of the code contained within the `protect` capture block. Any `handle` capture blocks contained within the `protect` capture blocks will be conditionally executed. However, Lasso requires these `handle` capture blocks to be present before the error occurs, so put them at the top of the `protect` capture block. The Lasso page will continue executing normally after the closing of the `protect` capture block. The `protect` capture blocks can be used for the following purposes: - To protect a portion of a page so that any errors that would normally result in an error message being displayed to the user are instead handled in the internal `handle` capture blocks. - To provide advanced flow control in a page. Code within the `protect` capture blocks is executed normally until a `fail` signal is encountered. The code then jumps immediately to the internal `handle` block. Protect a Portion of a Page from Errors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Wrap the portion of the page that needs to be protected in a `protect` capture block. Any internal errors that Lasso reports will be caught by the `protect` capture block and not reported to the end user. A `handle` capture block should be included to handle the error if necessary. In the following Lasso code an attempt is made to set a variable "myVar" to "null". However, if the variable has not been previously declared, an error would be reported, and the page would not continue processing. Since the code is executed within a `protect` capture block, no error is reported, and the `protect` capture block exits silently while the Lasso page resumes execution after the `protect` block. :: protect => { $myVar = null } Use protect with Custom Errors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following example shows a `protect` capture block that surrounds code containing two `fail_if` statements with custom error codes "-1" and "-2". A `handle` block at the start of the `protect` is set to intercept either of these custom error codes. This `handle` block will only execute if one of the `fail_if` methods executes successfully. :: protect => {^ handle => {^ if(error_code == -1) '... Handle custom error -1 ...' else(error_code == -2) '... Handle custom error -2 ...' else '... Another error has occurred ...' /if ^} 'Before the fail_if\n' local( condition_one = false, condition_two = true ) fail_if(#condition_one, -1, 'Custom error -1') fail_if(#condition_two, -2, 'Custom error -2') '\nAfter the fail_if' ^} // => // Before the fail_if // ... Handle custom error -2 ...