Handling Exceptions

Contact Us or call 1-877-932-8228
Handling Exceptions

Handling Exceptions

There are two types of exceptions in ColdFusion: compiler exceptions and runtime exceptions.

Compiler Exceptions

Compiler exceptions occur when a ColdFusion page cannot run at all because of some error in the code. For example, a compiler exception could be caused by any of the following:

  • missing angle bracket
  • an extraneous pound sign (#)
  • a missing required attribute
  • an attribute that doesn't belong

The following page will not compile:

Code Sample:

Errors/Demos/CompilerException.cfm
<cfif></cfif>

Part of the resulting error page is shown below:

The suggestions are generally not very helpful; however, in most cases the cause of a compiler exception is not too difficult to identify. Sometimes on pages with a lot of code, it can be difficult to locate the problem, especially if it is caused by a missing or extra close tag in code with a lot of nested tags. To illustrate, take a look at the following page.

Code Sample:

Errors/Demos/CompilerException2.cfm
<cfset a = "dog">
<cfset b = "cat">
<cfset c = "mouse">
<cfset d = "horse">
<cfset e = "cow">
<cfset f = "pig">
<cfset g = "donkey">

<cfif true>
<cfoutput>#a#</cfoutput>
<cfif true>
<cfif true>
<cfoutput>#b#</cfoutput>
</cfif>
<cfoutput>#c#</cfoutput>
<cfif true>
<cfif true>
<cfoutput>#d#</cfoutput>
</cfif>
<cfif true>
<cfoutput>#e#</cfoutput>
</cfif>
</cfif>
<cfoutput>#f#</cfoutput>
</cfif>
</cfif>
<cfoutput>#g#</cfoutput>
</cfif>

For simplicity, we have used "true" where a condition would be, but imagine that these conditions might be true or false under different circumstances.

Part of the resulting error page is shown below:

So, you're missing a start <cfif>. How do you identify which one? Or perhaps the real problem is that you have one too many close </cfif> tags.

One problem with this type of error is that you can get rid of the exception, but leave yourself with bad logic. For example, you could simply remove the last </cfif>. The exception goes away and the page displays: "dog cat mouse horse cow pig donkey".

But, suppose that you want the output to read: "dog cat mouse pig donkey". This kind of problem can be tricky to solve and unfortunately there is no simple answer, but we have a few recommendations that should make your coding life easier.

  1. Indent your code. This seems like a no brainer, but we see a lot of code written by experienced developers that is impossible to read simply because it isn't laid out nicely. Dreamweaver has a great "Apply Source Formatting" feature (under the Commands menu) to help lay out the code, but we recommend indenting as you write as it will help you avoid these types of errors in the first place.
  2. Nest your code sensibly. For example, don't use multiple <cfoutput> tags when one will do the trick.
  3. Use comments. Everybody recommends them, but they are used too infrequently. Comments will help you identify problems in your code and will allow you to focus on the solution. Even small comments can be helpful.

We have made some changes to our animals page:

Code Sample:

Errors/Demos/CompilerException2-formatted.cfm
<cfset a = "dog">
<cfset b = "cat">
<cfset c = "mouse">
<cfset d = "horse">
<cfset e = "cow">
<cfset f = "pig">
<cfset g = "donkey">

<cfoutput>
<cfif true>
	#a# <!---dog--->
	<cfif true>
		<cfif true>
			#b#<!---cat--->
			<cfif true>
				#c#<!---mouse--->
					<cfif true>
						#d#<!---horse--->
					</cfif>
					<cfif true>
						#e#<!---cow--->
					</cfif>
				</cfif>
				#f#<!---pig--->
			</cfif>
		</cfif>
		#g#<!---donkey--->
	</cfif>
</cfif>
</cfoutput>

The error hasn't been fixed, but now it is a lot easier to identify the problem. We know that we want the output to read "dog cat mouse pig donkey". We do not want "horse" and "cow" to be output. There are at least a couple of ways we can solve this. One is shown below:

Code Sample:

Errors/Demos/CompilerException2-fixed.cfm
<cfset a = "dog">
<cfset b = "cat">
<cfset c = "mouse">
<cfset d = "horse">
<cfset e = "cow">
<cfset f = "pig">
<cfset g = "donkey">

<cfoutput>
<cfif true>
	#a# <!---dog--->
	<cfif true>
		<cfif true>
			#b#<!---cat--->
			<cfif true>
				#c#<!---mouse--->
				<cfif false>
					<cfif true>
						#d#<!---horse--->
					</cfif>
					<cfif true>
						#e#<!---cow--->
					</cfif>
				</cfif>
				#f#<!---pig--->
			</cfif>
		</cfif>
		#g#<!---donkey--->
	</cfif>
</cfif>
</cfoutput>

Runtime Exceptions

Runtime exceptions are errors that are caught at the time the code is executed. They can be handled at the site level, at the application level, and at the page level. In this section, we will look at handling runtime exceptions at the site and application levels. In the next section we will look at page-level structured error handling.

Missing Template Handler Page

In ColdFusion Administrator, under Server Settings -> Settings, you can specify a missing template handler. Usually, you'll use this to provide a more friendly error. You may want to include your navigation bars on the template to make it easier for the users to find what they are looking for.

Site-wide Error Handler Page

In ColdFusion Administrator, under Server Settings > Settings, you can specify a site-wide error handler. This page can contain CFML, but you should nest anything potentially dangerous in try/catch blocks, which we will discuss shortly. The following example logs the error, returns an error to the screen (probably with too much information), and emails the site administrator an error dump. Note that the site-wide error handler will be used for compiler exceptions as well.

Code Sample:

Errors/Demos/SiteWideErrorPage.cfm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Oops!</title>
<style type="text/css">
	.Label {margin-top:10px; font-weight:bold; width:200px;}
	.Details {margin-left:10px; font-style:italic; width:500px;}
</style>
</head>
<body>
<h1>Oops!</h1>
<p>Sorry, we have experienced and error.</p>
<cftry>
	<!---LOG ERROR--->
	<cflog
		text="#ERROR.Diagnostics#, #ERROR.HTTPReferer#, #ERROR.Template##ERROR.QueryString#"
		log="application" type="Error">   
	<!---OUTPUT ERROR INFORMATION - may not want to do this on a live application--->
	<cfoutput>
		<div class="Label">Time of Error:</div>
		<div class="Details">#DateFormat(ERROR.DateTime)# at #TimeFormat(ERROR.DateTime)#</div>
		
		<div class="Label">Diagnostic Information:</div>
		<div class="Details">#ERROR.Diagnostics#</div>
		
		<div class="Label">Referrer:</div>
		<div class="Details">#ERROR.HTTPReferer#</div>
		
		<div class="Label">Template Causing Error:</div>
		<div class="Details">#ERROR.Template#?#ERROR.QueryString#</div>
	</cfoutput>
<cfcatch>
	No information available.
</cfcatch>
</cftry>

<!---SEND EMAIL TO SITE ADMINISTRATOR--->
<cftry>
	<cfmail to="admin@webucator.com" subject="#ERROR.Template# error" type="html" from="errors@webucator.com">
		<cfdump var="#ERROR#">
	</cfmail>
	<hr/>
	<p>The site administrator has been informed.</p>
	<cfcatch type="any">
		<cftry>
			<hr/>
			<cfoutput>
				<p>Please email the site administrator at 
				<a href="mailto:admin@webucator.com">admin@webucator.com</a>.</p>
			</cfoutput>
			<cfcatch type="any"></cfcatch>
		</cftry>
	</cfcatch>
</cftry>
</body>
</html>

Run Errors/Demos/SiteWideErrorDemo.cfm, which tries to read an undefined variable, in your browser and you will get the following result:

The logged error (in cfusion/cfusion-ear/cfusion-war/WEB-INF/cfusion/logs/application.log) will read something like:

"Error","jrpp-14","08/12/06","15:26:51","WEBUCATORCFM","Element FOO is undefined in VARIABLES. <br>The error occurred on line 6., , /Courseware/CFM201/ClassFiles/Errors/Demos/SiteWideErrorDemo.cfm"

Handling Errors with <cferror>

The <cferror> tag, which generally goes in the Application.cfm file, is used to indicate custom error templates for different types of errors. The type is specified with <cferror>'s type attribute. Possible values are:

  1. validation - has to do with server-side form validation, which we are not covering here.
  2. exception - displayed when runtime exceptions occur. You can use different templates for different types of exceptions.
  3. request - serves as a backup if errors occur in exception error templates. You cannot use CFML tags in this template, but you may output error variables by enclosing them in pound signs (e.g, #ERROR.Template#).

The following example shows a simple Application.cfm file that makes use of <cferror>. It is followed by examples of an exception error template and a request error template.

Code Sample:

Errors/Demos2/Application.cfm
<cfapplication sessionmanagement="yes" clientmanagement="yes" name="ErrorDemos">

<cferror type="exception" template="ErrorException.cfm" mailto="admin@webucator.com">
<cferror type="request" template="ErrorRequest.cfm" mailto="admin@webucator.com">
<cferror type="validation" template="ErrorValidation.cfm" mailto="admin@webucator.com">

Code Sample:

Errors/Demos2/ErrorException.cfm
<html>
<head>
	<title>Exception</title>
</head>

<body>
<h1>Exception Error!</h1>
<cfoutput>
<table border="1">
	<tr>
		<th>Name</th>
		<th>Value</th>
	</tr>
	<tr>
		<td>Error.Browser</td>
		<td>#Error.Browser#</td>
	</tr>
	<tr>
		<td>Error.DateTime</td>
		<td>#Error.DateTime#</td>
	</tr>
	<tr>
		<td>Error.Diagnostics</td>
		<td>#Error.Diagnostics#</td>
	</tr>
	<tr>
		<td>Error.GeneratedContent</td>
		<td>#Error.GeneratedContent#</td>
	</tr>
	<tr>
		<td>Error.HTTPReferer</td>
		<td>#Error.HTTPReferer#</td>
	</tr>
	<tr>
		<td>Error.MailTo</td>
		<td>#Error.MailTo#</td>
	</tr>
	<tr>
		<td>Error.QueryString</td>
		<td>#Error.QueryString#</td>
	</tr>
	<tr>
		<td>Error.Template</td>
		<td>#Error.Template#</td>
	</tr>
	<tr>
		<td>Error.RemoteAddress</td>
		<td>#Error.RemoteAddress#</td>
	</tr>
	<tr>
		<td>Error.Type</td>
		<td>#Error.Type#</td>
	</tr>
	<tr>
		<td>Error.RootCause</td>
		<td>#Error.RootCause#</td>
	</tr>
	<tr>
		<td>Error.Message</td>
		<td>#Error.Message#</td>
	</tr>
</table>
</cfoutput>
</body>
</html>

Code Sample:

Errors/Demos2/ErrorRequest.cfm
<html>
<head>
	<title>Request Error</title>
</head>

<body>
<h1>Request Error!</h1>

<table border="1">
	<tr>
		<th>Name</th>
		<th>Value</th>
	</tr>
	<tr>
		<td>Error.Browser</td>
		<td>#Error.Browser#</td>
	</tr>
	<tr>
		<td>Error.DateTime</td>
		<td>#Error.DateTime#</td>
	</tr>
	<tr>
		<td>Error.Diagnostics</td>
		<td>#Error.Diagnostics#</td>
	</tr>
	<tr>
		<td>Error.GeneratedContent</td>
		<td>#Error.GeneratedContent#</td>
	</tr>
	<tr>
		<td>Error.HTTPReferer</td>
		<td>#Error.HTTPReferer#</td>
	</tr>
	<tr>
		<td>Error.MailTo</td>
		<td>#Error.MailTo#</td>
	</tr>
	<tr>
		<td>Error.QueryString</td>
		<td>#Error.QueryString#</td>
	</tr>
	<tr>
		<td>Error.Template</td>
		<td>#Error.Template#</td>
	</tr>
	<tr>
		<td>Error.RemoteAddress</td>
		<td>#Error.RemoteAddress#</td>
	</tr>
</table>

</body>
</html>

To generate an exception error, open any of the following files:

Code Sample:

Errors/Demos2/CauseException1.cfm
<cfinclude template="Missing.cfm">

Code Sample:

Errors/Demos2/CauseException2.cfm
<cf_foo>

Code Sample:

Errors/Demos2/CauseException3.cfm
<cfquery datasource="NoSuchDS"></cfquery>

To generate a request error, run any of the files above after doing one of the following:

  1. Comment out the exception error template in Errors/Demos2/Application.cfm.
  2. Make the ColdFusion code in Errors/Demos2/ErrorException.cfm invalid.

Error Variables

Exception and request errors share the following variables:

Exception and Request Error Variables
Variable Description
ERROR.browser The user's browser.
ERROR.dateTime The date and time of the error.
ERROR.diagnostics Detailed diagnostic information.
ERROR.generatedContent Any content generated by the request before the error occurred.
ERROR.HTTPReferer The referring page, if any.
ERROR.mailTo The email address of the administrator as set in the <cferror> tag.
ERROR.queryString Query string of the request, if any.
ERROR.remoteAddress The IP address if the user's machine.
ERROR.template The page being executed when the error occurred.

In addition, exception errors have these additional variables:

Exception-only Error Variables
Variable Description
ERROR.message Message associated with the exception.
ERROR.rootCause A structure containing the data returned by <cfcatch>.
ERROR.tagContext An array of structures containing information for each tag that is currently open.
ERROR.type The exception type.

Handling Errors with the onError Method

The onError method of the Application.cfc component works much like the <cferror> tag. The method gets two arguments:

  1. An exception structure.
  2. The name of the Application.cfc method in which the error occurred. This will be blank unless the error occurred in some of the code in the Application.cfc file.

The method is generally used to log errors and to display a friendly error message. It can also be used to email information about the error to the site administrator. A sample is shown below.

Code Sample:

Errors/Demos3/Application.cfc
<cfcomponent>
<cfset THIS.name = "ErrorDemos">
<cffunction name="onRequestStart">	
	<!---Uncomment the tag below to cause an exception in this file--->
	<!---<cf_foo>--->
</cffunction>

<cffunction name="onError" output="true">
	<cfargument name="Except" required="true"/>
	<cfargument name="EventName" type="String" required="true"/>
	
	<!---Log Errors--->
	<cfset Message = Except.message>
	<cfif Len(EventName)>
		<cfset Message = Message & " The error occurred in " & EventName & ".">
	<cfelse>
		<cfset Message = Message & " The error occurred in " & CGI.SCRIPT_NAME & ".">
	</cfif>
	<cflog file="#THIS.Name#" type="error" text="Message: #Message#">
	
	<!--- Throw validation errors to ColdFusion for handling. --->
	<cfif Find("coldfusion.filter.FormValidationException", ARGUMENTS.Except.StackTrace)>
		<cfthrow object="#except#">
	<cfelse>
		<!--- You can replace this cfoutput tag a friendlier error message. --->
		<cfoutput>
			<h1>Error Event: #EventName#</h1>
			<h2>Error details:</h2>
			<cfdump var="#except#">
		</cfoutput>
	</cfif>
</cffunction>
</cfcomponent>

If an uncaught exception occurs, the onError method is invoked. It does the following:

  1. Logs the error. If the exception occurred in an Application.cfc method, it reports the method name. Otherwise, it reports the path to the requested page. It uses the application name (THIS.name) as the name of the log file, so that it can be found easily.
  2. Determines if the error is a form validation exception, in which case, it turns the error over to ColdFusion to handle. If it is not, then it outputs an error message.
Next