One Step Beyond: CFERROR Custom Error Messages (with Something Extra)

By Bouton Jones

© 2009 Bouton Jones

 
 

About the Workshop

Custom Error Handler Templates in CF MX 7 and Above

This workshop is accessible for beginner ColdFusion developers but it will be innovative enough for the more advanced developers. The topic is error customization through CFERROR and the Application template (using CF MX 7.)

Typically, the default ColdFusion Error message is ugly and alarming.   Customizing error messages can make a more pleasant experience for the user and a more robust solution for the developer --- but they come with new challenges and liabilities.   While the basic technique in this workshop is straight from a Forta book, the presentation implements several improvements and techniques that Forta left out as well as tips for addressing some of the hidden challenges inherant with these techniques.

PLEASE NOTE: There are several methods for customizing error messages but this workshop will ONLY focus on CFERROR customization though the Application.cfm / Application.cfc file. Although at the end of the work shop I will list other methods that you are encouraged to look up online or in books.

 

Preface

This workshop assumes a beginner developer's understanding of ColdFusion. It assumes you can create a simple template, add a few CF tags, create a Aplication.cfm or Application.cfc template, and debug your errors. But while the target of this workshop is begining developers, I hope some of the more advanced users can benefit from a few innovations in this solution.   When I implemented the Custom Error procedure, I started with Chapter 19 "Introducing the Web Application Framework" (pgs. 542-551) in Macromedia ColdFusion MX 7 Web Application Construction Kit by Ben Forta & Raymond Camden. But I added a unique improvement --- or a least so I thought.

(After implementing this technique, I found that another developer had arrived at a similar solution before me:

CF Error Handling - A pinch of this, a pinch of that
By: Al DiMarzio, HB Graphics
Guilford, CT
http://www.hbgraphics.com/tips_tutorials/ 9-cf_error_error_handling.cfm#2

As the saying goes "Great minds think alike.")

 

Files

Rather than reinventing the wheel, I suggest you download the templates I've already created and debugged and adapt them to your own situations.

Download Custom Error Templates

 

Default ColdFusion Error Messages

Here are some screen captures of error messages before customization:

First Ugly Error Message

Second Ugly Error Message

Aren't they pretty?

[Hint: No.]

 

Benefits?

What are the benefits over the usual ColdFusion error messages?

  • More professional and attractive appearance. (Doesn't look broken.)

  • More user friendly.  Addresses the user directly with comprehensible information.

  • More comforting:  Reassures the user that we are aware of the problem and will act to fix it.

  • Faster:  Notifies the developer quicker.  (Usually before the client has time to call the application owner and the application owner has time to contact the developer)

  • More efficient:  Collects valuable information about a programming error for the developer without having the developer interview the user

  • More proactive:  Tracks user validation errors.  Is someone trying to crack your web form?  Are a lot of users having the same problem submitting a form?  (IE are several users consistently getting confused by the same instructions?)

 

Caveats

  • Two of the three custom error templates are limited in the ColdFusion tags and variables they can use. This limits their customization and functionality. (Fortunately there is a way around these limitation which this workshop will address. Thatis the part of the presentation that goes "beyond Forta.")

  • Custom error messages are less informative that the ugly default error messages. I recommend temporarily disabling the custom error messages once you're aware of an error and restore the templates once you've identified a solution.


  • You must debug the error templates before making them live. If you have any errors in the custom error templates when you call them though the CFERROR tags, they will generate an infinite loop: A blank browser window and a persistant "reload" noise.

 

Steps

Development can be broken down into five major steps.

  1. Create four or five new templates. The first three are the "Custom Error" Templates (a Request Error template, an Exception Error template, and a Validation Error template as described by Forta)

  2. Debug each template by opening them in a browser.

  3. Add the three CFERROR tags to your Application.cfs file. (Or your Application.cfm if you haven't gotten around to using Application.cfc.)

  4. Further test and debug on development. Don't wait for errors. Create errors where there are none.

  5. Further test and debug on production. Create errors even in applications that don't have any.

 

Definitions

Request Error
Handles any exception that is not otherwise-handled. The request error page runs after the CFML language processor finishes. As a result, the request error page cannot include CFML tags, but can display error page variables. A request error page is useful as a backup if errors occur in other error handlers.


Exception Error
Handles specific exception errors. You can specify individual error pages for different types of exceptions.


Validation Error
Handles server-side form field data validation errors. The validation error page cannot include CFML tags, but it can display error page variables. You can use this attribute only on the Application.cfm page. It has no effect when used on any other page. Therefore, you can specify only one validation error page per application, and that page applies to all server-side validation errors.

[Source: Adobe Livedocs]

 

Error Variables Info

(From Adobe Website)

The exception-handling template specified in the template attribute of the cferror tag contains one or more error variables. ColdFusion substitutes the value of the error variable when an error displays.

The following table lists the error variables:

Error Scope Variables
Template type
Error variable
Description
Exception
Request
Monitor
error.diagnostics
Detailed error diagnostics from ColdFusion Server.
error.mailTo
E-mail address of administrator notified (corresponds to the value set in the mailTo attribute of cferror).
error.dateTime
Date and time when the error occurred.
error.browser
Browser that was running when the error occurred.
error.generatedContent
The failed request's generated content.
error.remoteAddress
IP address of the remote client.
error.HTTPReferer
Page from which the client accessed the link to the page where the error occurred.
error.template
Page being executed when the error occurred.
error.queryString
URL query string of the client's request.
Validation
error.validationHeader
Text for header of validation message.
error.invalidFields
Unordered list of validation errors that occurred.
error.validationFooter
Text for footer of validation message.

[Source: Adobe Livedocs]

 

Step One: Making the Exception Error Template

The most effective means of developing a set of customized error message templates is to adapt a working set of templates to your own needs.  (BTW: It won't be necessary in this workshop to write down any of this code or variable names because the necessary files are availalble for download.) The Exception Error Template will use a special set or variables in the ERROR scope that help in debugging the error. In addition you can all of the other ColdFusion variables, attributes, and tags that can help you --- including the CGI variables and the CFMAIL tag.

Initial Exception Error Template
 

And here's the resulting error message (more or less):

 
Custom Error Message

 

Step One (Continued): Request and Validation Error Templates

Unfortunately, the code for the other two templates are more limited and less rebust.   The Request Error template and the Validation Error template only recognize a small set of CF variables (in the ERROR scope.)   They do not allow very many ColdFusion tags (such as the CFINCLUDE and CFMAIL), ColdFusion functions, or any other variables.   Notice that our customization is limited (no CFINCLUDE) and we can't send an email to the developer without the user's intervention (no CFMAIL.)

 

 

 

Bummer!

HOWEVER!   The Request Error template and the Validation Error template can utilize plain HTML form tags and JavaScript.   So it's possible for those templates to pass information about the errors to another ColdFusion template that is not restricted.   The second template can display the error in a customized format and send an email to the developer just like the Exception Error template!

Request Error Template
 
Validation Error Template

 

Side Note: Server Side and Client Side Data Validation

The Validation Error template is strictly for server side validation.   A best practice is to catch validation errors with a mixture of client side (JavaScript) and server side validation.   Most of us client side validation but we can augment it with server side validation in case the user turns off JavaScript --- or if the clint decides to forbid the use of JavaScript on it's networks.  (Heaven Forbid!)   Here's one quick and easy technique:

  1. Develop a template that uses CFFORM and CFINPUT tags to validate the form fields on the server. Be sure to write customized error messages that are easy to read and understand. Select the onServer option for the validateAt attribute.Access the pages over the intranet in a web browser.View the source.


  2. "Cut" the FORM markup in the source and "paste" it into the template (replacing the CFFORM and CFINPUT tags with FORM and INPUT tags.  Please note ColdFusion should have added new INPUT tags of the hidden type.


Before:

<cfform action="Test_for_SQL_Injection.cfm" method="post">
SSN: <cfinput name="SSN" id="SSN" type="text" validateat="onserver"
required="yes" message="Please enter a valid SSN"
validate="social_security_number">
<cfinput name="submit" type="submit" value="submit">
</cfform>

After:

<form action="Test_for_SQL_Injection.cfm" method="post">
SSN: <input name="SSN" id="SSN" type="text" validateat="onserver" required="yes"
message="Please enter a valid SSN" validate="social_security_number">
<input type='hidden' name='SSN_CFFORMSSN' value='Please enter a valid SSN'>
<input type='hidden' name='SSN_CFFORMREQUIRED' value='Please enter a valid SSN'>
<input name="submit" type="submit" value="submit">
</form>

Even if you don't like the validation JavaScript that ColdFusion generates or if it's against a policy (private or otherwise) to use canned JavaScript, you can still take advantage of ColdFusion's server side validation.

 

Step One (Continued): Monitor Errors

Some documentation online mentions the Monitor type error and suggests it as an attribute type for the CFERROR tag.

<CFERROR TYPE="MONITOR" TEMPLATE="MONITOR.cfm">

Don't use it.

Livedocs reads in part: "Macromedia recommends that customers do not use CFERROR type='monitor' within CFML templates."   It's depreciated.

 

Step One (Continued): the Fourth Template

As we've learned, the traditional implemenation of CFERROR templates is to create three custom error message templates. An improvement we can make is to add a fourth template which took the data from the three original templates, emailed the information to the developer and then displayed the information to the user.

What belongs in this fourth template?

  • CFPARAM tags for all variables in case crackers try to access the template directly. Or if a user makes a bookmark of the error page. Or something unexpected happens.


  • Optionally, a CFQUERY insert (See below)


  • CFMAIL email code to send a complete error message and diagnostic info to the developer without the user's intervention.


  • A mssage to the userthat is professional, conversational, and limits TMI. Maybe the message should include a request for the user to email the developer with details about the error.

SIDE NOTE: What is TMI? What does the user need to know?) Why ask the user to contact the developer if the developer is going to automajically get an email anyway? Because Redundancy is your friend. And your friend is redundancy. If you depend entirely on this solution to notify yourself of errors, inevitably it will fail.

Here's an example of the fourth template.

The Fourth Template: dspCustomError.cfm

 

Reducing Redundant Markup

Now we have two templates --- errException.cfm and the fourth template --- where we have customized the markup to match the appearance of the web site.   But is that necessary?   Really, all we have to do is customize the appearance of the fourth template and make sure all errors are displayed through that template (including the exception errors.)

Revised Exception Error Template
 
Revised Fourth Template: dspCustomError.cfm

 

New Problem: Reloading the Error Display Screen

But there is a potential problem with this fourth template:   A user might reload the page.   What would happen then?

The problem now is that the mailto code --- and any other code in the form --- will be performed every time the user reloads the page.   The developer will get an identical email message every time the user reloads the screen.

One solution is to split the fourth template into two new templates. One template will send an email to the developer with details about the error and then pass the data on. The other template will display the error message to the user.

If the user reload the screen with the error message all that will happen is that the error message will refresh.   No other processing will occur.   The developer will get no additional email.

actError.cfm: Error Email Template
 
dspError.cfm: Error Display Template

 

Fixing the Broken Back Link

Please note that using a interrupt / redirect in the way shown will disable the back button in your browser because the proceeding page will redirect you back to the error display page.   One solution to this problem is as follows.   In the Display template, include the following HTML in place of the "FORM.ValidationFooter" variable:

   <FORM>
        <INPUT type="button" value="Please Click Here To Go Back" onClick="history.go(-3)">
   </FORM>


(FYI: I've tried several variations of "Please go <a href="javascript:history.back(3)">back</a> and correct the problem" but this is the only back link that I have been able to get to work in this situation.)

 

Error Tracking through a Database

It's possible to save the error incidents to a database by adding CFQUERY tag to the fourth template.   That way the developers can track their errors in a dashboard application.

 

Lagniappe: Adding Server Diagnostics

<cfset pmData = GetMetricData("PERF_MONITOR")>
<cfoutput>
        <p>Current PerfMonitor data is: <br />
        InstanceName:   #pmData.InstanceName# <br />
        PageHits:      #pmData.PageHits# <br />
        ReqQueued:       #pmData.ReqQueued# <br />
        DBHits:    #pmData.DBHits# <br />
        ReqRunning:       #pmData.ReqRunning# <br />
        ReqTimedOut: #pmData.ReqTimedOut# <br />
        BytesIn:       #pmData.BytesIn# <br />
        BytesOut:       #pmData.BytesOut# <br />
        AvgQueueTime: #pmData.AvgQueueTime# <br />
        AvgReqTime:       #pmData.AvgReqTime# <br />
        AvgDBTime:       #pmData.AvgDBTime# </p>
</cfoutput>

 

Step Two: Debug the New Templates

Debug each template by adding CFPARAM tags and opening each template in a browser. (Doing this before adding the CFERROR tags will minimize cascading error messages in which the error template generates a vicious infinite loop.) Temporarily use CFPARAM tag to assign default values for all the individual values in the ERROR scope. (Example: <cfparam name="ERROR.ValidationHeader" default="">) NOTE: This extra step will save you a lot of grief! Please DO IT! Once you're done, comment out or delete the CFPARAM tags in the request error and validation error templates. Following the next step, they won't play nice with the CFPARAM tag.

 

Step Three: Add three CFERROR tags

None of these templates actually work yet.   We need to follow one more step:   Place the following tags in Application.cfm (or Application.cfc):

<CFERROR TYPE="REQUEST" TEMPLATE="errRequest.cfm" MAILTO="Webmaster@MyDomain.com">
<CFERROR TYPE="EXCEPTION" TEMPLATE="errException.cfm" MAILTO="Webmaster@MyDomain.com">
<CFERROR TYPE="VALIDATION" TEMPLATE="errValidation.cfm" MAILTO="Webmaster@MyDomain.com">

After this step, the templates will be called when you encounter errors. TIP: Add the Request tag first and debug that corresponding template before you add the other two CFERROR tags.

 

Steps Four and Five: Testing

Test the procedures on development and production. Intentionally create errors for each error type: exception, request, and validation. (It will be necessary to comment out the exception CFERROR to check the request error.)

<!--- Deliberately prompting an exception error by calling a variable that has not been declared --->
<cfoutput>#UndefinedVariable#</cfoutput>
<!--- Deliberatley prompt a valiation error --->
<cfform action="home.cfm?action=validationerror" method="post">
        <cfinput type="hidden" name="integer" value="abc" validate="integer"
                message="Please enter an integer in the
                Integer field" validateat="onserver">
        <cfinput type="submit" value="Validation Error Msg." name="submit">
</cfform>

 

Extra Step for Fusebox

Add a "display error" fuseaction to home.cfm / main.cfm / index.cfm:

<cfcase value="dspError">
  <cfinclude template="dspError.cfm">
</cfcase>

Using fusebox, that's the extent of the customiztion. It's not necessary modify any of the new files any further.

 

Another Option: Portal Wide Error Handling

[NOTE: I haven't tested this yet.]

  • Change fuseaction in home.cfm / main.cfm / index.cfm to the following:
    <cfcase value="dspError">
      <cfinclude template="../portal/dspError.cfm">
    </cfcase>


  • Place dspError.cfm in portal directory.

 

Other Error Customization Techniques

The following techniques are outside the scope of this presentation but they are straight forward and covered in detail by readily available sources (such as Forta.)

  • Specifying template in IIS or Apache to catch web server errors such as 404 File Not Found

  • Specifying a missing template handler in ColdFusion Administrator.

  • Using client side and server side Form Data Validation with CFFORM and CFINPUT

  • Error Handling with CFTRY and CFCATCH

  • Custom coding your own functions with CFIF statements

  • Validating variables with CFPARAM

  • The IsValid Function: Function that performs data validation just like the CFPARAM tag and supports all the new data types in CFPARAM. (New with CF 7)
    <CFIF IsValid("integer", url.value)>
      Valid integer!
     <CFELSE>
      Invalid Integer!
    </CFIF>


 

In Conclusion

I hope you all got something useful out of this presentation. If you try out this solution and come up with improvements, I'd love to hear about them.

Thank you!

 

top