Handling runtime exceptions with ColdFusion tags

Exceptions include any event that disrupts the normal flow of instructions in a ColdFusion page, such as failed database operations, missing include files, or developer-specified events. Ordinarily, when ColdFusion encounters an exception, it stops processing and displays an error message or an error page specified by a cferror tag or the Administrator Site-wide Error Handler setting. However, you can use ColdFusion's exception handling tags to catch and process runtime exceptions directly in ColdFusion pages.

This ability to handle exceptions directly in your application pages enables your application to do the following:

Exception-handling tags

ColdFusion provides the exception-handling tags listed in the following table:
Tag
Description
cftry
If any exceptions occur while processing the tag body, look for a cfcatch tag that handles the exception, and execute the code in the cfcatch tag body.
cfcatch
Execute code in the body of this tag if the exception caused by the code in the cftry tag body matches the exception type specified in this tag's attributes.
Used in cftry tag bodies only.
cfthrow
Generate a user-specified exception.
cfrethrow
Exit the current cfcatch block and generates a new exception of the same type.
Used only in cfcatch tag bodies.

Using cftry and cfcatch tags

The cftry tag allows you to go beyond reporting error data to the user:

For example, you can use cftry to catch errors in code that enters data from a user registration form to a database. The cfcatch code could do the following:

  1. Retry the query, so the operation succeeds if the resource was only temporarily unavailable.
  2. If the retries fail:

Code that accesses external resources such as databases, files, or LDAP servers where resource availability is not guaranteed is a good candidate for using try/catch blocks.

Try/catch code structure

In order for your code to directly handle an exception, the tags in question must appear within a cftry block. It is a good idea to enclose an entire application page in a cftry block. You then follow the cftry block with cfcatch blocks, which respond to potential errors. When an exception occurs within the cftry block, processing is thrown to the cfcatch block for that type of exception.

Here is an outline for using cftry and cfcatch to handle errors:

<cftry>
  Put your application code here ...
  <cfcatch type="exception type1">
    Add exception processing code here ...
  </cfcatch>
  <cfcatch type="exception type2">
    Add exception processing code here ...
  </cfcatch>
  .
  .
  .
  <cfcatch type="Any">
    Add exception processing code appropriate for all other exceptions
here ...
  </cfcatch>
</cftry>

Try/catch code rules and recommendations

Follow these rules and recommendations when you use cftry and cfcatch tags:

Exception information in cfcatch blocks

Within the body of a cfcatch tag, the active exception's properties are available in the cfcatch structure.

Standard cfcatch variables

The following table describes the variables that are available in most cfcatch blocks:
Property variable
Description
cfcatch.Detail
A detailed message from the CFML compiler. This message, which can contain HTML formatting, can help to determine which tag threw the exception.
The cfcatch.Detail value is available in the CFScript cfcatch statement as the exceptionVariable parameter.
cfcatch.ErrorCode
The cfthrow tag can supply a value for this code through the errorCode attribute. For Type="Database", cfcatch.ErrorCode has the same value as cfcatch.SQLState.
Otherwise, the value of cfcatch.ErrorCode is the empty string.
cfcatch.ExtendedInfo
Custom error message information. This is returned only to cfcatch tags for which the type attribute is Application or a custom type.
Otherwise, the value of cfcatch.ExtendedInfo is the empty string.
cfcatch.Message
The exception's default diagnostic message, if one was provided. If no diagnostic message is available, this is an empty string.
The cfcatch.Messagee value is included in the value of the CFScript catch statement exceptionVariable parameter.
cfcatch.RootCause
The Java servelet exception reported by the JVM as the cause of the "root cause" of the exception.
cfcatch.TagContext
An array of structures structure containing information for each tag in the tag stack The tag stack consists of each tag that is currently open.
cfcatch.Type 
The exception's type, returned as a string.

Note:   If you use cfdump to display the cfcatch variable, the display does not include variables that do not have values.

The cfcatch.TagContext variable contains an array of tag information structures. Each structure represents one level of the active tag context at the time when ColdFusion detected the exception. That is, there is one structure for each tag that is open at the time of the exception. For example, if the exception occurs in a tag on a custom tag page, the tag context displays information about the called custom tag and the tag in which the error occurs.

The structure at position 1 in the array represents the currently executing tag at the time the exception was detected. The structure at position ArrayLen(cfcatch.tagContext) represents the initial tag in the stack of tags that were executing when the compiler detected the exception.

The following table lists the tagContext structure attributes:
Entry
Description
Column
Obsolete (retained for backwards compatibility). Always 0.
ID
The tag in which the exception occurred. Exceptions in CFScript are indicated by two question marks (??). All custom tags, including those called directly, are identified as cfmodule.
Line
The line on the page in which the tag is located.
Raw_Trace
The raw Java stack trace for the error.
Template
The pathname of the application page that contains the tag.
Type
The type of page;it is always a ColdFusion page.

Database exceptions

The following additional variables are available whenever the exception type is database:
Property variable
Description
cfcatch.NativeErrorCode
The native error code associated with this exception. Database drivers typically provide error codes to assist in the diagnosis of failing database operations. The values assumed by cfcatch.NativeErrorCode are driver-dependent.
If no error code is provided, the value of cfcatch.nativeErrorCode is -1. The value is 0 for queries of queries.
cfcatch.SQLState
The SQLState code associated with this exception. Database drivers typically provide error codes to assist in the diagnosis of failing database operations. SQLState codes are more consistent across database systems than native error codes.
If the driver does not provide an SQLState value, the value of cfcatch.SQLState is -1.
cfcatch.Sql
The SQL statement sent to the data source.
cfcatch.queryError
The error message as reported by the database driver.
cfcatch.where
If the query uses the cfqueryparam tag, query parameter name-value pairs.

Expression exceptions

Property variable
Description
cfcatch.ErrNumber
An internal expression error number, valid only when type="Expression".
The following variable is only available for Expression exceptions:

Locking exceptions

The following additional information is available for exceptions related to errors that occur in cflock tags:
Property variable
Description
cfcatch.lockName
The name of the affected lock. This is set to "anonymous" if the lock name is unknown.
cfcatch.lockOperation
The operation that failed. This is set to "unknown" if the failed operation is unknown.

Missing include exceptions

The following additional variable is available if the error is caused by a missing file specified by a cfinclude tag:
Property variable
Description
cfcatch.missingFileName
The name of the missing file.

Using cftry: an example

The following example shows the cftry and cfcatch tags. It uses the CompanyInfo data source used in many of the examples in this book and a sample included file, includeme.cfm.

If an exception occurs during the cfquery statement's execution, the application page flow switches to the cfcatch type="Database" exception handler. It then resumes with the next statement after the cftry block, once the cfcatch type="Database" handler completes.

Similarly, the cfcatch type="MissingInclude" block handles exceptions raised by the cfinclude tag.

<!--- Wrap code you want to check in a cftry block --->
<cfset EmpID=3>
<cfparam name="errorCaught" default="">
<cftry>
  <cfquery name="test" datasource="CompanyInfo">
    SELECT Dept_ID, FirstName, LastName
    FROM Employee
    WHERE Emp_ID=#EmpID#
  </cfquery>

  <html>
  <head>
  <title>Test cftry/cfcatch</title>
  </head>
  <body>
  <cfinclude template="includeme.cfm">
  <cfoutput query="test">
    <p>Department: #Dept_ID#<br>
    Last Name: #LastName#<br>
    First Name: #FirstName#</p>
  </cfoutput>

<!--- Use cfcatch to test for missing included files. --->
<!---   Print Message and Detail error messages. --->
<!--- Block executes only if a MissingInclude exception is thrown. --->
  <cfcatch type="MissingInclude">
    <h1>Missing Include File</h1>
    <cfoutput>
    <ul>
      <li><b>Message:</b> #cfcatch.Message#
      <li><b>Detail:</b> #cfcatch.Detail#
      <li><b>File name:</b> #cfcatch.MissingFileName#
    </ul>
    </cfoutput>
    <cfset errorCaught = "MissingInclude">
  </cfcatch>

<!--- Use cfcatch to test for database errors.--->
<!---   Print error messages. --->
<!--- Block executes only if a Database exception is thrown. --->
  <cfcatch type="Database">
    <h1>Database Error</h1>
    <cfoutput>
    <ul>
      <li><b>Message:</b> #cfcatch.Message#
      <li><b>Native error code:</b> #cfcatch.NativeErrorCode#
      <li><b>SQLState:</b> #cfcatch.SQLState#
      <li><b>Detail:</b> #cfcatch.Detail#
      </ul>
    </cfoutput>
    <cfset errorCaught = "Database">
  </cfcatch>

<!--- Use cfcatch with type="Any" --->
<!--- to find unexpected exceptions. --->
  <cfcatch type="Any">
    <cfoutput>
      <hr>
      <h1>Other Error: #cfcatch.Type#</h1>
      <ul>
        <li><b>Message:</b> #cfcatch.Message#
        <li><b>Detail:</b> #cfcatch.Detail#
      </ul>
    </cfoutput>
    <cfset errorCaught = "General Exception">
  </cfcatch>
  
</body>
</html>
</cftry>

Testing the code

Use the following procedure to test the code:

  1. Make sure there is no includeme.cfm file and display the page. The cfcatch type="MissingInclude" block displays the error.
  2. Create a nonempty includeme.cfm file and display the page. If your database is configured properly, you should see an employee entry and not get any error.
  3. In the cfquery tag, change the line:
    FROM Employee
    

    to:

    FROM Employer
    

    Display the page. This time the cfcatch type="Database" block displays an error message.

  4. Change Employer back to Employee.

    Change the cfoutput line:

    <p>Department: #Dept_ID#<br>
    

    to:

    <p>Department: #DepartmentID#<br>
    

    Display the page. This time the cfcatch type="Any" block displays an error message indicating an expression error.

  5. Change DepartmentID back to Dept_ID and redisplay the page. The page displays properly.

    Open \CFusion\Log\MyAppPage.log in your text editor. You should see a header line, an initialization line, and four detail lines, similar to the following:

    "Severity","ThreadID","Date","Time","Application","Message"
    "Information","web-0","11/20/01","16:27:08",,"C:\Neo\servers\default\logs\
    MyAppPage.log initialized"
    "Information","web-0","11/20/01","16:27:08",,"Page: /neo/MYStuff/NeoDocs/
    cftryexample.cfm Error: MissingInclude"
    "Information","web-1","11/20/01","16:27:32",,"Page: /neo/MYStuff/NeoDocs/
    cftryexample.cfm Error: "
    "Information","web-0","11/20/01","16:27:49",,"Page: /neo/MYStuff/NeoDocs/
    cftryexample.cfm Error: Database"
    "Information","web-1","11/20/01","16:28:21",,"Page: /neo/MYStuff/NeoDocs/
    cftryexample.cfm Error: General Exception"
    "Information","web-0","11/20/01","16:28:49",,"Page: /neo/MYStuff/NeoDocs/
    cftryexample.cfm Error: "
    

Reviewing the code

The following table describes the code:
Code
Description
<cfset EmpID=3>
<cfparam name="errorCaught" default="">

Initializes the employee ID to a valid value. An application would get the value from a form or other source.
Sets the default errorCaught variable value to the empty string (to indicate no error was caught).
There is no need to put these lines in a cftry block.
<cftry>
<cfquery name="test"
    datasource="CompanyInfo">
  SELECT Dept_ID, FirstName, LastName
  FROM Employee
  WHERE Emp_ID=#EmpID#
</cfquery>
Starts the cftry block. Exceptions from here to the end of the block can be caught by cfcatch tags.
Queries the CompanyInfo database to get the data for the employee identified by the EmpID variable.
<html>
<head>
<title>Test cftry/cfcatch</title>
</head>
<body>
<cfinclude template="includeme.cfm">
<cfoutput query="test">
  <p>Department: #Dept_ID#<br>
  Last Name: #LastName#<br>
  First Name: #FirstName#</p>
</cfoutput>
Begins the HTML page. This section contains all the code that displays information if no errors occur.
Includes the includeme.cfm page.
Displays the user information record from the test query.
<cfcatch type="MissingInclude">
  <h1>Missing Include File</h1>
  <cfoutput>
  <ul>
    <li><b>Message:</b> #cfcatch.Message#
    <li><b>Detail:</b> #cfcatch.Detail#
    <li><b>File name:</b>
      #cfcatch.MissingFilename#
  </ul>
  </cfoutput>
  <cfset errorCaught = "MissingInclude">
</cfcatch>
Handles exceptions thrown when a page specified by the cfinclude tag cannot be found.
Displays cfcatch variables, including the ColdFusion basic error message, detail message, and the name of the file that could not be found.
Sets the errorCaught variable to indicate the error type.
<cfcatch type="Database">
  <h1>Database Error</h1>
  <cfoutput>
  <ul>
    <li><b>Message:</b> #cfcatch.Message#
    <li><b>Native error code:</b>
      #cfcatch.NativeErrorCode#
    <li><b>SQLState:</b> #cfcatch.SQLState#
    <li><b>Detail:</b> #cfcatch.Detail#
    </ul>
  </cfoutput>
  <cfset errorCaught = "Database">
</cfcatch>
Handles exceptions thrown when accessing a database.
Displays cfcatch variables, including the ColdFusion basic error message, the error code and SQL state reported by the databases system, and the detailed error message.
Sets the errorCaught variable to indicate the error type.

<cfcatch type="Any">
  <cfoutput>
    <hr>
    <h1>Other Error: #cfcatch.Type#</h1>
    <ul>
      <li><b>Message:</b> #cfcatch.message#
      <li><b>Detail:</b> #cfcatch.Detail#
    </ul>
  </cfoutput>
  <cfset errorCaught = "General Exception">
</cfcatch>
Handles any other exceptions generated in the cftry block.
Since the error can occur after information has displayed (in this case, the contents of the include file), draws a line before writing the message text.
Displays the ColdFusion basic and detailed error message.
Sets the errorCaught variable to indicate the error type.
</body>
</html>
</cftry>
Ends the HTML page, then the cftry block.

Using the cfthrow tag

You can use the cfthrow tag to raise your own, custom exceptions. When you use the cfthrow tag, you specify any or all of the following information:
Attribute
Meaning
type
The type of error. It can be a custom type that has meaning only to your application, such as InvalidProductCode. You can also specify Application, the default type. You cannot use any of the predefined ColdFusion error types, such as Database or MissingTemplate.
message
A brief text message indicating the error.
detail
A more detailed text message describing the error.
errorCode
An error code that is meaningful to the application. This field is useful if the application uses numeric error codes.
extendedInfo
Any additional information of use to the application.

All of these values are optional. You access the attribute values in cfcatch blocks and Exception type error pages by prefixing the attribute with either cfcatch or error, as in cfcatch.extendedInfo. The default ColdFusion error handler displays the message and detail values in the Message pane and the remaining values in the Error Diagnostic Information pane.

Catching and displaying thrown errors

The cfcatch tag catches a custom exception when you use any of the following values for the cfcatch type attribute:

Similarly, if you specify any of these types in a cferror tag, the specified error page will display information about the thrown error.

Because the cfthrow tag generates an exception, a Request error handler or the Site-wide error handler can also display these errors.

Custom error type name hierarchy

You can name custom exception types using a method that is similar to Java class naming conventions: domain name in reverse order, followed by project identifiers, as in the following example:

<cfthrow
  type="com.myCompany.myApp.Invalid_field.codeValue"
  errorcode="Dodge14B">

This fully qualified naming method is not required; you can use shorter naming rules, for example, just myApp.Invalid_field.codeValue, or even codeValue.

This naming method is not just a convention however. The ColdFusion Server uses the naming hierarchy to select from a possible hierarchy of error handlers. For example, assume you use the following cfthrow statement:

<cfthrow type="MyApp.BusinessRuleException.InvalidAccount">

Any of the following cfcatch error handlers would handle this error:

<cfcatch type="MyApp.BusinessRuleException.InvalidAccount">
<cfcatch type="MyApp.BusinessRuleException">
<cfcatch type="MyApp">

The handler that most exactly matches handles the error. Therefore, in this case, the MyApp.BusinessRuleException.InvalidAccount handler gets invoked. However, if you used the following cfthrow tag:

<cfthrow type="MyApp.BusinessRuleException.InvalidVendorCode

the MyApp.BusinessRuleException handler receives the error.

The type comparison is no case-sensitive.

When to use cfthrow

Use the cfthrow tag when your application can identify and handle application-specific errors. One typical use for the cfthrow tag is in implementing custom data validation. The cfthrow tag is also useful for throwing errors from a custom tag page to the calling page.

For example, on a form action page or custom tag used to set a password, the application can determine whether the password entered is a minimum length, or contains both letters and number, and throw an error with a message that indicates the password rule that was broken. The cfcatch block handles the error and tells the user how to correct the problem.

Using the cfrethrow tag

The cfrethrow tag lets you create a hierarchy of error handlers. It tells ColdFusion to exit the current cfcatch block and "rethrow" the exception to the next level of error handler. Thus, if an error handler designed for a specific type of error cannot handle the error, it can rethrow the error to a more general-purpose error handler. The rethrow tag can only be used in a cfcatch tag body.

The cfrethrow tag syntax

The following pseudo-code shows how you can use the cfrethrow tag to create an error-handling hierarchy:

<cftry>
  <cftry>
    Code that might throw a database error
    <cfcatch Type="Database">
      <cfif Error is of type I can Handle>
        Handle it
      <cfelse>
        <cfrethrow>
      </cfif
    </cfcatch>
  </cftry>
  <cfcatch Type="Any">
    General Error Handling code
  </cfcatch>
</cftry>

Although this example uses a Database error as an example, you can use any cfcatch type attribute in the innermost error type.

Follow these rules when you use the rethrow tag:

Example: using nested tags, cfthrow, and cfrethrow

The following example shows many of the techniques discussed in this chapter, including nested cftry blocks and the cfthrow and cfrethrow tags. The example includes a simple calling page and a custom tag page:

The calling page

The calling page represents a section from a larger application page. To keep things simple, the example hard-codes the name to be looked up.

<cftry>
  <cf_getEmps EmpName="Jones">
  <cfcatch type="myApp.getUser.noEmpName">
    <h2>Oops</h2>
    <cfoutput>#cfcatch.Message#</cfoutput><br>
  </cfcatch>
</cftry>
<cfif isdefined("getEmpsResult")>
  <cfdump var="#getEmpsResult#">
</cfif>

Reviewing the code

The following table describes the code:
Code
Description
<cftry>
  <cf_getEmps EmpName="Jones">
In a cftry block, calls the cf_getEmps custom tag (getEmps.cfm).
<cfcatch type="myApp.getUser.noEmpName">
    <h2>Oops</h2>
    <cfoutput>#cfcatch.Message#</cfoutput><br>
  </cfcatch>
</cftry>
If the tag throws an exception indicating that it did not receive a valid attribute, catches the exception and displays a message, including the message variable set by the cfthrow tag in the custom tag.
<cfif isdefined("getEmpsResult")>
<cfdump var="#getEmpsResult#">
</cfif>
If the tag returns a result, uses the cfdump tag to display it. (A production application would not use cfdump.)

The custom tag page

The custom tag page searches for the name in the database and returns any matching records in a getEmpsResult variable in the calling page. It includes several nested cftry blocks to handle error conditions. For a full description, see "Reviewing the code", following the example:

Save the following code as getEmps.cfm in the same directory as the calling page.

<!--- If the tag didn't pass an attribute, throw an error to be handled by
      the calling page --->
<cfif NOT IsDefined("attributes.EmpName")>
  <cfthrow Type="myApp.getUser.noEmpName"
    message = "Last Name was not supplied to the cf_getEmps tag.">
  <cfexit method = "exittag">
<!--- Have a name to look up --->
<cfelse>
<!--- Outermost Try Block --->
  <cftry>

<!--- Inner Try Block --->
    <cftry>
<!--- Try to query the main database and set a caller variable to the result --->
      <cfquery Name = "getUser" DataSource="CompanyInfo">
        SELECT * 
        FROM Employee
        WHERE LastName = '#attributes.EmpName#'
      </cfquery>
      <cfset caller.getEmpsResult = getuser>
<!--- If the query failed with a database error, check the error type
      to see if the database was found --->      
      <cfcatch type= "Database">
        <cfif (cfcatch.SQLState IS "S100") OR (cfcatch.SQLState IS
          "IM002")>

<!--- If the database wasn't found, try the backup database --->
<!--- Use a third-level Try block --->
          <cftry>
            <cfquery Name = "getUser" DataSource="CompanyInfoBackup">
              SELECT * 
              FROM Employee
              WHERE LastName = '#attributes.EmpName#'
            </cfquery>
             <cfset caller.getEmpsResult = getuser>

<!--- If still get a database error, just return to the calling page
      without setting the caller variable. There is no cfcatch body.
      This might not be appropriate in some cases. 
      The Calling page ends up handling this case as if a match was not
      found --->
             <cfcatch type = "Database" />
<!--- Still in innermost try block. Rethrow any other errors to the next
      try block level --->            
            <cfcatch type = "Any">
              <cfrethrow>
            </cfcatch>
          </cftry>

<!--- Now in second level try block.
      Throw all other types of Database exceptions to the next try 
        block level --->
        <cfelse>
          <cfrethrow>
        </cfif>
      </cfcatch>
<!--- Throw all other execptions to the next try block level --->
      <cfcatch type = "Any">
          <cfrethrow>
      </cfcatch>
    </cftry>

<!--- Now in Outermost try block. 
     Handle all unhandled exceptions, including rethrown exceptions, by
      displaying a message and exiting to the calling page.--->
    <cfcatch Type = "Any">
      <h2>Sorry</h2>
      <p>An unexpected error happened in processing your user inquiry.
        Please report the following to technical support:</p>
      <cfoutput>
        Type: #cfcatch.Type#
        Message: #cfcatch.Message#
      </cfoutput>
      <cfexit method = "exittag">
    </cfcatch>
  </cftry>  
</cfif>

Reviewing the code

The following table describes the code:
Code
Description
<cfif NOT IsDefined("attributes.EmpName")>
  <cfthrow Type="myApp.getUser.noEmpName"
    message = "Last Name was not supplied to 
    the cf_getEmps tag.">
  <cfexit method = "exittag">
Makes sure the calling page specified an EmpName attribute. If not, throws a custom error that indicates the problem and exits the tag. The calling page handles the thrown error.
<cfelse>
  <cftry>
If the tag has an EmpName attribute, does the remaining work inside an outermost try block. The cfcatch block at its end handles any otherwise- uncaught exceptions.
<cftry>
  <cfquery Name = "getUser"
    DataSource="CompanyInfo">
    SELECT * 
    FROM Employee
    WHERE LastName = '#attributes.EmpName#'
  </cfquery>
  <cfset caller.getEmpsResult = getuser>
Starts a second nested try block. This block catches exceptions in the database query.
If there are no exceptions, sets the calling page's getEmpsResult variable with the query results.
<cfcatch type= "Database">
  <cfif (cfcatch.sqlstate IS "S100") OR 
    (cfcatch.sqlstate IS "IM002")>
    <cftry>
      <cfquery Name = "getUser" DataSource=
      "CompanyInfoBackup"
        SELECT * 
        FROM Employee
        WHERE LastName = '#attributes.EmpName#'
      </cfquery>
      <cfset caller.getEmpsResult = getuser>
If the query threw a Database error, checks to see if the error was caused by an inability to access the database (indicated by an SQLState variable value of S100 or IM002).
If the database was not found, starts a third nested try block and tries accessing the backup database. This try block catches exceptions in this second database access.
If the database inquiry succeeds, sets the calling page's getEmpsResult variable with the query results.
  <cfcatch type = "Database" />

If the second database query failed with a database error, gives up silently. Because the Database type cfcatch tag does not have a body, the tag exits. The calling page does not get a getEmpsResult variable. It cannot tell whether the database had no match or an unrecoverable database error occurred, but it does know that no match was found.
  <cfcatch type = "Any">
    <cfrethrow>
  </cfcatch>
</cftry>
If the second database query failed for any other reason, throws the error up to the next try block.
Ends the innermost try block
  <cfelse>
    <cfrethrow>
  </cfif>
</cfcatch>
In the second try block, handles the case in which the first database query failed for a reason other than a failure to find the database.
Rethrows the error up to the next level, the outermost try block.
  <cfcatch type = "Any">
    <cfrethrow>
  </cfcatch>
</cftry>
In the second try block, catches any errors other exceptions and rethrows them up to the outermost try block.
Ends the second try block.
    <cfcatch Type = "Any">
      <h2>Sorry</h2>
      <p>An unexpected error happened in processing
      your user inquiry.
        Please report the following to technical support:</p>
      <cfoutput>
        Type: #cfcatch.Type#
        Message: #cfcatch.Message#
      </cfoutput>
    <cfexit method = "exittag">
    </cfcatch>
  </cftry>  
</cfif>
In the outermost try block, handles any exceptions by displaying an error message that includes the exception type and the exception's error message. Because there was no code to try that is not also in a nested try block, this cfcatch tag handles only errors that are rethrown from the nested blocks.
Exits the custom tag and returns to the calling page.
Ends the catch block, try block, and initial cfif block.

Testing the code

To test the various ways errors can occur and be handled in this example, try the following:

Comments