I've done more than a few posts recently about error handling and robust exception information, so I thought I'd write up one blog entry that can serve as a nice guide for folks to bookmark. By using "Complete" in the title, I've also virtually assured that I will forget something critical, so please, send suggestions for what I've missed. Let's get started.
What is the point of this guide? Unless you are a perfect code, there is a chance that your ColdFusion application will have errors in it. The question is - what are you doing with your errors? What was the last error that occurred on your site? If I asked you how many errors your site threw yesterday, could you answer with 100% complete accuracy? I'd be willing to bet most people would say no. Shoot, I know I couldn't answer that. So what do we do to help resolve this issue? The first thing I want you to do is to create an error. Create a new CFM file named errortest.cfm. Insert one line into it:1 <cfoutput>#xfhdshsdhj#</cfoutput>
The point of this template is to create an error. Unless you actually have a variable defined with that ugly name, the template will error out. Upload it to your server and run it with your browser.
One of three things will happen:
1) You will get an error with the full path shown, like below. This shows that you have not added error management to your application, and that you have Enabled Robust Exception information in your ColdFusion Administrator. Stop reading this blog entry, go to your Admin, and disable it. Now. (Please note that this guide is intended for a production machine environment. Obviously you can keep this setting on in development. I do.)
2) You will get an error with no path shown. This is slightly better. It still shows that you haven't added error management to your application though.
3) You get an "error page". By "error page" I mean a page saying that an error occurred, but displayed in your standard site layout, or close to it. That's good. You should still continue to read though as I'm going to discuss things that should normally be in an error handler.
Ok, before going on - delete the page you just uploaded. I'd be willing to bet a good 40-50% of us upload test.cfm type files to our servers and forget to delete them. I've never done that. Really.
So - lets talk error handling now. You have two high level options. The first is to set an error template in the ColdFusion administrator:
If you specify a template here, than ColdFusion will run the template when an error occurs. In general though I wouldn't recommend setting the template here.
Your second option - and what I recommend - is to the handle the errors specifically in your application. How? If you are on an older ColdFusion server and only have access to Application.cfm, then you want to the use the CFERROR tag. You can use these tags in Application.cfc as well, but I recommend onError for that. I'm going to cover both though.
A full description of cferror may be found in the docs. I'm going to give you the Ray Camden quickie guide to it. The cferror basically lets you specify an template to run when a type of error occurs. There are 3 main types of errors it monitors: Exception, Request, and Validation. Forget about validation. Don't use it. Exception is the type of error we are most familiar with. It is what I call the 'basic' error. Request is the more serious error. It can occur when your error handler itself screws up. I call this the "Oh S***" error (seriously). It has special restrictions on it I'll discuss in a second. First though, let's look at the syntax you would use in your Application.cfm file:
1 <cfapplication name="rayrules">
2
3 <cferror type="exception" template="error.cfm">
4 <cferror type="request" template="error_request.cfm">
As you can see - it's pretty simple stuff. I basically said - for the Exception (again, think 'normal' error), run error.cfm. For the Oh Crap error, run error_request.cfm.
If you run any CFM again - you will immediately get an error stating that these files do not exist. You should create blank ones for the time being.
Now for the details. The error.cfm template is a normal CFM page. But it has access to a special variable: ERROR. This variable is a structure that contains a lot of information about the error. What you get there will also depend on the error. SQL errors for example will have different values in the structure than a simple runtime error. Let's just do a quick dump.
2
3 <cferror type="exception" template="error.cfm">
4 <cferror type="request" template="error_request.cfm">
1 <cfdump var="#error#">
If you run your error test again (you may have to reupload it if you deleted it like I suggested, just don't forget to remove it later!), you will see something like this:
I'm not going to list every field - again, check the cferror syntax doc for that. The item you will most care about normal is cferror.message. This is the simplest representation of the error and will be most useful for logging. The diagnostics value gives more detail including a line number which is handy during development.
So what now? Well first off - you probably don't want your public site showing a dump. Let's begin by outputting a nice message to the user. Here is the new version of error.cfm:
1 We are so sorry. Something went wrong. We are working on it now.
Obviously you can mark that up with nice HTML, use your custom tag layout wrapper, etc. This handles letting the user know something bad happened. At bare minimum, this is better than showing naked errors to the user, but we should do something with the error. I recommend two things.
Log the error. For some odd reason, ColdFusion will nicely log an unhandled error, but will not log a handled error. I believe Blue Dragon logs the error anyway. Since ColdFusion won't log it, we should:
1 <cflog file="myapperrorlog" text="#error.message# - #error.diagnostics#">
Note that I've specified the message and diagnostics variable. This is a bit of a duplication since diagnostics information will have the same information as message, but I like the shortness of the message value. You could log more than this obviously, but since this is a log file, we don't want to overdue it here.
THe next thing we should do is email the error. This is something I've covered before on the blog, so some of you may know my feelings on this already, but what I typically do is email me the entire error structure. I also include other structures so I can see what else was going on:
1 <cfsavecontent variable="errortext">
2 <cfoutput>
3 An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.query_string#<br />
4 Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
5
6 <cfdump var="#error#" label="Error">
7 <cfdump var="#form#" label="Form">
8 <cfdump var="#url#" label="URL">
9
10 </cfoutput>
11 </cfsavecontent>
12
13
14 <cfmail to="bugs@myproject.com" from="root@myproject.com" subject="Error: #error.message#" type="html">
15 #errortext#
16 </cfmail>
I create my message within a cfsavecontent (more on why in a second), and then mail it. Don't forget the type=html. Now as you can guess, this creates a pretty big email. If you get a 1000 of these, you will be suffering, but consider it incentive to fix the darn bug ASAP. You could also add a dump of the session scope if you wanted, or CGI. Basically, it is better to send more information then you need then to be wanting for more. Having all this detail gives you a better idea of what is going on when the error occurred.
So why the cfsavecontent? One trick I'll often do is to skip the email if I'm currently logged in as an admin on the site. I'll do a quick check, and if I'm an admin, I'll display the error on screen. This lets me see the error more quickly than waiting for an email.
So all together now, here is the error.cfm file:
2 <cfoutput>
3 An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.query_string#<br />
4 Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
5
6 <cfdump var="#error#" label="Error">
7 <cfdump var="#form#" label="Form">
8 <cfdump var="#url#" label="URL">
9
10 </cfoutput>
11 </cfsavecontent>
12
13
14 <cfmail to="bugs@myproject.com" from="root@myproject.com" subject="Error: #error.message#" type="html">
15 #errortext#
16 </cfmail>
1 We are so sorry. Something went wrong. We are working on it now.
2
3 <cflog file="myapperrorlog" text="#error.message# - #error.diagnostics#">
4
5 <cfsavecontent variable="errortext">
6 <cfoutput>
7 An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.query_string#<br />
8 Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
9
10 <cfdump var="#error#" label="Error">
11 <cfdump var="#form#" label="Form">
12 <cfdump var="#url#" label="URL">
13
14 </cfoutput>
15 </cfsavecontent>
16
17
18 <cfmail to="bugs@myproject.com" from="root@myproject.com" subject="Error: #error.message#" type="html">
19 #errortext#
20 </cfmail>
Now for fun, try modifying your error.cfm. Change the first cfdump tag to a cfpoo tag. If you rerun your template, you will see a blank page. Remember that we created a blank error_request.cfm file earlier? This is what is running now. Basically, ColdFusion has noticed that we had an error, and then our error management had an error, and it's thrown it's hands up in the air and given up. We are now in the request template. The request template has special rules - the most important being - no CFML. That's right - you can't cflog. You can't email the error. You can - however - output error variables. You don't use cfoutput, you just include them. Consider this sample:
2
3 <cflog file="myapperrorlog" text="#error.message# - #error.diagnostics#">
4
5 <cfsavecontent variable="errortext">
6 <cfoutput>
7 An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.query_string#<br />
8 Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
9
10 <cfdump var="#error#" label="Error">
11 <cfdump var="#form#" label="Form">
12 <cfdump var="#url#" label="URL">
13
14 </cfoutput>
15 </cfsavecontent>
16
17
18 <cfmail to="bugs@myproject.com" from="root@myproject.com" subject="Error: #error.message#" type="html">
19 #errortext#
20 </cfmail>
1 This went wrong: #error.diagnostics#
This will display:
This went wrong: Unknown tag: cfpoo. ColdFusion cannot determine how to process the tag cfpoo because the tag is unknown and not in any imported tag libraries. The tag name might be misspelled. The error occurred on line -1.That's all you can do really. But guess what - I wouldn't do that. Remember - we don't want to reveal any sensitive information to our users, including what caused an error. So what do I recommend? Go to your site and view source. This will give you the HTML result of one of your pages. Find the content and replace it with a "We're sorry" type message like we used in error.cfm. Then save that HTML. Basically you are creating a static page. This means that if you change your layout, you have to regenerate your error_request.cfm page. Of course, you could just not use any layout at all, but most people want their pages to have a standard look and feel. Unfortunately, nothing is logged when this error happens. So what can you do? One thing to consider is checking the web server log files to see when the file is run. If you see it running often, then double check your error.cfm file for possible errors. If worse comes to worse, temporarily wrap your error.cfm itself in a try/catch and see what shows up when you dump cfcatch. I'm open to suggestions here - but there is a reason they (ok, I) call this the "Oh Crap" error. Ok, so I've covered quite a bit of information here, but it applies to Application.cfm and CFERROR. What if you are using Application.cfc? Well one thing to remember is that you can just as easily put CFERROR tags inside your Application.cfc file. That is allowed, and I've done that before. But what if you want to use the onError method? In general - a lot of what I said about the Exception type for CFERROR applies here. You want to present a nice message to your user. You want to log the error. You want to email the error to yourself. But there are some subtle differences. Consider this very simple onError:
1 <cffunction name="onError" returnType="void" output="true">
2 <cfargument name="exception" required="true">
3 <cfargument name="eventname" type="string" required="true">
4 <cfdump var="#arguments#"><cfabort>
5 </cffunction>
All I've done here is dump all the arguments sent in. Now go back to your error file (the one you made to throw errors) and change it to this:
2 <cfargument name="exception" required="true">
3 <cfargument name="eventname" type="string" required="true">
4 <cfdump var="#arguments#"><cfabort>
5 </cffunction>
1 <h1>Hellow World</h1>
2 <cfoutput>#xfhdshsdhj#</cfoutput>
Run it in your browser, and you will see this:
2 <cfoutput>#xfhdshsdhj#</cfoutput>
Notice that the HTML before the error is displayed in the browser. If we had used a nice error message instead of the dump, the user would see both. This can result in oddly formatted pages. What you can do instead is simply handle the error and cflocate to the a nicer page:
1 <cffunction name="onError" returnType="void" output="true">
2 <cfargument name="exception" required="true">
3 <cfargument name="eventname" type="string" required="true">
4 <cfset var errortext = "">
5
6 <cflog file="myapperrorlog" text="#arguments.exception.message#">
7
8 <cfsavecontent variable="errortext">
9 <cfoutput>
10 An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.query_string#<br />
11 Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
12
13 <cfdump var="#arguments.exception#" label="Error">
14 <cfdump var="#form#" label="Form">
15 <cfdump var="#url#" label="URL">
16
17 </cfoutput>
18 </cfsavecontent>
19
20 <cfmail to="bugs@myproject.com" from="root@myproject.com" subject="Error: #arguments.exception.message#" type="html">
21 #errortext#
22 </cfmail>
23
24 <cflocation url="error.cfm">
25
26 </cffunction>
All I did was take the code from my original error.cfm file and place it in here. The Exception argument here looks a bit different. No diagnostics key. So I just logged the message for now. My error.cfm file now only contains the message:
2 <cfargument name="exception" required="true">
3 <cfargument name="eventname" type="string" required="true">
4 <cfset var errortext = "">
5
6 <cflog file="myapperrorlog" text="#arguments.exception.message#">
7
8 <cfsavecontent variable="errortext">
9 <cfoutput>
10 An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.query_string#<br />
11 Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
12
13 <cfdump var="#arguments.exception#" label="Error">
14 <cfdump var="#form#" label="Form">
15 <cfdump var="#url#" label="URL">
16
17 </cfoutput>
18 </cfsavecontent>
19
20 <cfmail to="bugs@myproject.com" from="root@myproject.com" subject="Error: #arguments.exception.message#" type="html">
21 #errortext#
22 </cfmail>
23
24 <cflocation url="error.cfm">
25
26 </cffunction>
1 We are so sorry. Something went wrong. We are working on it now.
Lets recap:
- Do a quick test to figure out how your application responds to errors.
- If robust exeception information is displayed, turn it off.
- Use CFERROR or onError to handle errors.
- Do your own logging, and email yourself a detailed report.
Comment 1 written by existdissolve on 5 December 2007, at 3:28 PM
Thanks so much for taking the time to post this. I have been looking for something exactly like this for a while now, and it has helped to provide a context for attacking the error-handling issue that is still daunting for a relatively new CF developer such as myself.
Thanks for all that you do!
Comment 2 written by david buhler on 5 December 2007, at 4:07 PM
...do these two dumps need to be prefaced with "StructKeyExists":
<cfdump var="#form#" label="Form">
<cfdump var="#url#" label="URL">
?
Comment 3 written by Michael Sharman on 5 December 2007, at 4:19 PM
In which case you could use either methods shown above, those being a global error template in CF Admin or a 'request/oh crap' cferror in onRequestStart()
Nice post Ray
Comment 4 written by Bruce on 5 December 2007, at 5:10 PM
I've been using cfdump in the email that goes out when an error occurs as you illustrate in your Application.cfc code above.
One issue that has always bothered me (mainly because I'm AR) is the extra output in the email that cfdump causes. All the text for the javascript functions that control toggling just get dumped into the email's body. All I want to have in my email body are the contents of the structures (Exception, Form, Session, CGI, etc).
I've tried using cfloop with collection = but the problem is that some of the structures contain complex elements (arrays, another structure) as values so the cfloop collection = fails.
This cfdump issue actually caused me a problem with one of my email clients. That POP3 email client would not display the output from cfdump because with the extra javascript code text outputted the HTML for the email body was not well formed. So I got just part of the error message and no data from the structures.
So if anyone has a good replacement for cfdump to output the complete contents of the structures (Exception, Form, Session, CGI) in a manner that will display correctly in an HTML formatted email, I'd love to hear about it.
Comment 5 written by Raymond Camden on 5 December 2007, at 5:16 PM
<cfdump var="#application#" format="text">
Specifically, format=.
Comment 6 written by Ryan Heldt on 5 December 2007, at 5:32 PM
Comment 7 written by david buhler on 5 December 2007, at 5:35 PM
<!--- outputs as text--->
<cfdump var="#cgi#" format="text">
vs
<!--- outputs as HTML --->
<cfdump var="#cgi#">
I posted a bug with Adobe.
The "format" attribute should be a killer way to get detailed errors on the mobile phone (at last!).
Comment 8 written by Bruce on 5 December 2007, at 7:41 PM
Comment 9 written by Gualtiero Sappa on 6 December 2007, at 7:28 AM
We do something similar on our production server and this is very useful to notify us errors in real time and to provide a better look & feel to error pages.
Comment 10 written by K2 on 6 December 2007, at 8:46 AM
Great article, thanks. I wanted to print it but found no good way to do so. Do you have a printer-friendly feature that is not turned on? Would be awesome to be able to print these in a printer-friendly way.
k2
Comment 11 written by Raymond Camden on 6 December 2007, at 9:20 AM
Comment 12 written by Raymond Camden on 6 December 2007, at 9:27 AM
Comment 13 written by CoolJJ on 6 December 2007, at 9:58 AM
It looks like the format option is supposed to be used with the output attribute. That is when it defaults to text.
@Bruce
I imagine you could write a more complex error.cfm template and then just do a test on each collection item in your cfloop to determine its type and then handle the output appropriatly via the isSimpleValue(), isArray(), isStruct(), isXML() functions.
CoolJJ
Comment 14 written by franz s.fsc on 6 December 2007, at 10:01 AM
Nice and helpful post. If i implement it on MX7 the whole mail is visible on the page and all cf code shows on view source?
what am i missing?
Comment 15 written by Raymond Camden on 6 December 2007, at 10:14 AM
@Franz - so if you remember, I mentioned there were two types of errors. Exception=You can use CFML, Request=You Can't. Did you only use the Request one? Remember to use 2 different templates.
Comment 16 written by Franz Schlienger on 6 December 2007, at 10:22 AM
I use
<cferror type="exception" template="error.cfm">
<cferror type="request" template="error_request.html">
the x.cfm is online if you want to check. Look at the <cfset x = 1> in the page source.
Thanks franz
Comment 17 written by Raymond Camden on 6 December 2007, at 10:29 AM
Comment 18 written by Franz Schlienger on 6 December 2007, at 10:49 AM
I changed it back. It shows only on my live but not on the development server. Witch cf server setting could cause it?
Thanks
Comment 19 written by K2 on 6 December 2007, at 10:50 AM
K2
Comment 20 written by Rick Smith on 6 December 2007, at 10:53 AM
Comment 21 written by Raymond Camden on 6 December 2007, at 10:56 AM
Comment 22 written by K2 on 6 December 2007, at 11:02 AM
Comment 23 written by Raymond Camden on 6 December 2007, at 11:07 AM
Try this out. :)
Comment 24 written by Franz Schlienger on 6 December 2007, at 11:09 AM
That's what i have. The first 2 lines of application.cfm are:
<cferror type="exception" template="error.cfm">
<cferror type="request" template="error_request.html">
Comment 25 written by Raymond Camden on 6 December 2007, at 11:13 AM
Comment 26 written by K2 on 6 December 2007, at 12:05 PM
How do I go about creating a Request or Validation error to test this.
Comment 27 written by Raymond Camden on 6 December 2007, at 12:08 PM
Don't worry about validation errors. They are used when you use CF's built in form checking, which no one uses, and no one should use.
Comment 28 written by K2 on 6 December 2007, at 12:39 PM
The function:
<code>
<cffunction name="onError" returntype="void" output="true">
<cfargument name="Exception" required="true">
<cfargument name="EventName" type="string" required="true">
<cferror type="request" template="error/RequestErrorDetail.cfm">
<cfinclude template="error/ErrorDetail.cfm">
</cffunction>
</code>
This does work, but I find it much more useful to error trap the exception error page this way.
<code>
<cffunction name="onError" returntype="void" output="true">
<cfargument name="Exception" required="true">
<cfargument name="EventName" type="string" required="true">
<cftry>
<cfinclude template="error/ErrorDetail.cfm">
<cfcatch type="any">
<cfdump var="cfcatch">
</cfcatch>
</cftry>
</cffunction>
</code>
This way I can email the request error (or any other error the 'error' page generates) using the cfcatch scope or do whatever I want with it. Is there a problem doing it this way?
Comment 29 written by Jason Brookins on 6 December 2007, at 12:43 PM
I'm still a bit cloudy on how to incorporate handling your "oh, crap" error into the onError in Application.cfc. Do you have a quick version of the onError function that you can post to show how you handle both?
Comment 30 written by Raymond Camden on 6 December 2007, at 1:43 PM
Comment 31 written by Michael White on 7 December 2007, at 5:39 PM
Comment 32 written by Niall on 7 December 2007, at 7:03 PM
I have implemented the error handling code in my Application.cfc using the onError() method and all works fine except for the <cferror> tag in the onRequestStart() method to trap the request error.
I have included my Application.cfc for reference:
<cfcomponent output="false">
<cfset this.name = "mytestportal">
<cfset this.applicationTimeout = createTimeSpan(0,0,20,0)>
<cfset this.clientManagement = true>
<cfset this.clientStorage = "cookie">
<cfset this.loginStorage = "session">
<cfset this.sessionManagement = true>
<cfset this.sessionTimeout = createTimeSpan(0,0,20,0)>
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfreturn true>
</cffunction>
<cffunction name="onApplicationEnd" returnType="void" output="false">
<cfargument name="applicationScope" required="true">
</cffunction>
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true">
<cferror type="request" template="dspErrorRequest.cfm">
<cfreturn true>
</cffunction>
<cffunction name="onRequest" returnType="void">
<cfargument name="thePage" type="string" required="true">
<cfinclude template="#arguments.thePage#">
</cffunction>
<cffunction name="onRequestEnd" returnType="void" output="true">
<cfargument name="thePage" type="string" required="true">
</cffunction>
<cffunction name="onError" returnType="void" output="false">
<cfargument name="exception" required="true">
<cfargument name="eventname" type="string" required="true">
<cfset var errortext = "" />
<cfset var mailToAddr = "developersEmail@developers.com" />
<cfset var mailFromAddr = "applicationEmail@appDomain.com" />
<!---
IF DEVELOPMENT, SIMPLY USE THIS...NO NEED TO SEND EMAILS!
<cfdump var="#arguments#"/><cfabort/>
--->
<cflog file="#this.name#" text="#ARGUMENTS.exception.message# - #ARGUMENTS.exception.RootCause.Message#" />
<!--- BUILD THE EMAIL CONTENT --->
<cfsavecontent variable="errorText">
<cfoutput>
An error occurred: http://#cgi.server_name##cgi.script_name#?#cgi.que... />
Time: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br />
<cfdump var="#ARGUMENTS.exception#" label="Error">
<cfdump var="#FORM#" label="FORM">
<cfdump var="#URL#" label="URL">
<cfdump var="#SESSION#" label="SESSION">
<cfdump var="#CGI#" label="CGI">
</cfoutput>
</cfsavecontent>
<!--- E-MAIL THE ERROR TO THE DEVELOPER(S) --->
<cfmail to="#mailToAddr#" from="#mailFromAddr#" subject="Error: #ARGUMENTS.exception.message#" type="html">
#errorText#
</cfmail>
<cflocation url="dspError.cfm">
</cffunction>
<cffunction name="onSessionStart" returnType="void" output="false">
</cffunction>
<cffunction name="onSessionEnd" returnType="void" output="false">
<cfargument name="sessionScope" type="struct" required="true">
<cfargument name="appScope" type="struct" required="false">
</cffunction>
</cfcomponent>
When I added an invalid CFML tag in my error handler page:
<cfpoo >
kjhgjhg
</cfpoo>
I simply get the standard coldfusion error message:
A tag starting with 'CF' has been detected. This tag is not supported by this version of ColdFusion. Please verify your typo and try again.
Is there something I'm doing wrong or can you confirm the exact method for trapping these coldfusion errors, if possible?
Thanks!
Comment 33 written by Michael White on 8 December 2007, at 10:52 AM
Comment 34 written by Raymond Camden on 8 December 2007, at 10:57 AM
Comment 35 written by Michael White on 8 December 2007, at 11:11 AM
Comment 36 written by Raymond Camden on 8 December 2007, at 11:15 AM
Comment 37 written by Michael White on 8 December 2007, at 11:18 AM
Comment 38 written by Raymond Camden on 8 December 2007, at 11:25 AM
Comment 39 written by Michael White on 8 December 2007, at 3:05 PM
Comment 40 written by Ryan LeTulle on 10 December 2007, at 1:58 PM
Thank you Ray.
See you at Sakura. :)
Comment 41 written by Paul Davis on 12 December 2007, at 11:35 AM
One thing that we have been doing is to clean up the error text into a simple readable email and log format by parsing the error structure, there is still an option to dump if the need is there (our error handler is a component that exists in the application layer and is called from the application.cfc). But normally you can get what you need through a little parsing which I find much easier to digest when coding.
Another thing that we do is check to make sure that things exist before we attempt to email them, for instance I have run into errors where parts of the session simply do not exist or even some of the application layer components, so I've learned to put a isdefined() check on almost anything that get's parsed. If it's not there then it's simply not provided, it's more work but in liue of a huge message it's very useful for us.
Thanks
-Paul-
Comment 42 written by Bruce on 12 December 2007, at 12:44 PM
Comment 43 written by David Whiterod on 3 February 2008, at 10:20 PM
Do you know of a way to access the (optional) errorcode and (custom) type cfthrow args from a (CFERROR) error handling page.
It looks like errorcode and type are only available within a cfcatch block and do not bubble up to the cferror page.
Cheers
David
Comment 44 written by Raymond Camden on 4 February 2008, at 9:52 AM
Comment 45 written by David Whiterod on 4 February 2008, at 8:51 PM
On further investigation, I didn't look hard enough.
Within a CFCATCH the errorcode etc is available (top-level) within the cfcatch struct. Once passed to a cferror template the error object is no longer in the top-level of the error struct but available at error.RootCause.
What started to trick me is cfcatch.type will report a custom error type but error.type (even when a custom error is specified) will always be 'coldfusion.runtime.CfErrorWrapper'.
(I'm using CF8,0,0,176276 Enterprise)
Cheers
David
Comment 46 written by Shama on 18 February 2008, at 3:28 PM
<cferror type="request" template="error_request.cfm"> to the onRequestStart() function in Application.cfc but it doesn't seem to catch the error and display the custom template. I still get the standard coldfusion error message. Any help would be greatly appreciated. Thanks!
Comment 47 written by Steve Clifton on 18 February 2008, at 4:28 PM
Comment 48 written by Raymond Camden on 18 February 2008, at 4:52 PM
Comment 49 written by Steve Clifton on 18 February 2008, at 5:04 PM
Unfortunately we are still running CF7 and plan to do so for a few more months. What is your solution for missing template handling on CF7, cos the setting in CF Administrator simply does not work on boxes hosting more than one site!
Thanks,
Steve
Comment 50 written by Raymond Camden on 18 February 2008, at 5:14 PM
Comment 51 written by Steven Waters on 20 February 2008, at 5:41 PM
Comment 52 written by Niall on 23 February 2008, at 5:51 PM
I have implemented a solution for the complete exception and request error handling - just haven't got round to posting it.
If you don't mind - and Ray doesn't mind me using this post for this - you can mail me directly for the source code to n.odoherty [at] niallodoherty [dot] com
These are in no way complete - but were intended to be used as a starting point for implemnting in new applications. Therefore there will be "some" changes required.
Comment 53 written by Raymond Camden on 24 February 2008, at 2:51 PM
Comment 54 written by mgwalk on 25 March 2008, at 12:59 PM
http://kb.adobe.com/selfservice/viewContent.do?ext...
Comment 55 written by xavier on 17 April 2008, at 4:36 PM
Now, with the new servers we started to have severe performance issues and to top that some data loss also was happening. It appeared as if data was rolled back. Today, we turned off the error handling and the servers are working like a charm now.
Now, we are not entirely sure if the error handling caused all the problems because we were also trying other things like rebuilding indexes for database tables. Anyone had similar issues? Can cftry cause this kind of data rollbacks?
Comment 56 written by Raymond Camden on 17 April 2008, at 5:13 PM
You do know that CF5 does support cferror, right? Why not just use that?
Comment 57 written by gary on 23 April 2008, at 6:50 AM
I love to have try/catch blocks on my error page as well, specifically early on.
There is not much worse than throwing an error on your error page while attempting to handle the email; logging for an error.
Dear user, while we were handling a system error another internal error occured, both have been noted
Comment 58 written by Carry on 27 April 2008, at 2:12 PM
Quote from the MX7 LiveDocs: "To ensure that error pages display successfully, avoid using the CFENCODE utility to encode pages that include the CFERROR tag."
OK, I'm concerned about CFCOMPILE with deploy option, not the the old cfencode, and I'm specifying my CFERROR tags in Application.cfc, onRequestStart. Also integrating this with sitewide error management using onError and CFCATCH. So I'm really wondering if a sitewide error management strategy can be impacted by the use of compile. Thank you!
Also, just for clarification: Am I correct in thinking that CFTHROW or CFTHROW will stop execution in it's tracks and there would be no need for a CFABORT in that context? Example without a throw: CFCATCH output something CFABORT /CFCATCH... Of course we would want to use the abort to stop further execution, if that is desired.
Alternative Example: CFCATCH throw or rethrow right here /CFCATCH... In this alternative example, am I correct in thinking that the CFABORT would be unnecessary to halt execution past the CFCATCH, since the CFTRHOW or CFRETHROW would stop execution here and redirect to the error management routines?
Thank you for your post and advice.
Comment 59 written by Mike on 5 June 2008, at 7:03 PM
Comment 60 written by Kim Andi on 2 September 2008, at 3:56 PM
I'm working on database conversions with several queries using ColdFusion.
I'm outputting the status of each group of queries when they begin and end. I have been hard coding the line numbers and would like to know if there is some CF variable that I can use to output the line numbers dynamically.
The problem is when I add code to the pages, the lines increase or decrease so the line numbers get screwed up.
I tried creating include files, but sometimes that's more work than it's worth.
Any ideas?
Thanks!
Comment 61 written by Raymond Camden on 5 September 2008, at 7:17 AM
Comment 62 written by Kim Andi on 5 September 2008, at 7:40 AM
I have this at the top of the page:
<cfflush interval="10">
<cfset nowtime = #timeformat(now(),"hh:mm:ss")#>
Then I have the elapsed time calculated in an include file
Then the hard coded line number is output to the screen with the elapsed time so we know how long each query takes to run.
The line numbers are so we can easily find the queries in the file. If the page halts for server time outs or failures, we can quickly get to that location and examine it.
What is "GetFoo"?
Comment 63 written by Raymond Camden on 5 September 2008, at 8:41 AM
getFoo was simply an example.
Comment 64 written by xavy on 9 September 2008, at 7:22 PM
<cferror type="exception" template="errorException.cfm">
<cferror type="request" template="errorRequest.cfm">
in my application.cfm. On a basic error (like the one above), the page that gets called is the errorRequest.cfm and of course no cfml gets executed. Is there any setting in my server that would cause this?
Thanks!
Comment 65 written by Raymond Camden on 9 September 2008, at 8:13 PM
Comment 66 written by xavy on 9 September 2008, at 9:36 PM
Thanks!
Comment 67 written by Michael Lasell on 16 September 2008, at 4:12 PM
ASP.NET would handle this without a blink.
Comment 68 written by Raymond Camden on 16 September 2008, at 4:20 PM
CF handles this w/o a blink too. ;) Unless I'm misreading you somehow.
Comment 69 written by EstebanD on 20 October 2008, at 1:02 PM
When logging or emailing the error I grab the relevant parts of the "error" structure.
On SQL errors I use error.RootCause.sql which reports the offending SQL. The problem is when using cfqueryparam the parameters are shown as (param 1)...(param X). How can I get the values of the parameters?
This is what I found in this regard: http://www.mail-archive.com/cfaussie@googlegroups.... but as you can notice is way too complicated.
Thank you
EstebanD
Comment 70 written by Raymond Camden on 20 October 2008, at 4:31 PM
Comment 71 written by Tim Garver on 11 November 2008, at 4:38 PM
I have a customer who has an older system, meaning it was coded in CF4
He used a LOT of <INPUT TYPE="HIDDEN" NAME="FIELD_REQUIRED"
VALUE="YOU MUST SELECT A VALUE">
instead of using client side validation.
He came to me a few months ago wanting to upgrade to CF7.
I knew these among many other lazy coding techniques would bit me in the but, and i urged my customer to fix all this prior to the upgrade.
So know he has a site with 1500 documents that have 3000 some odd hidden fields that need to be replaced.
When i setup his App.cfc, i used some generic error catching and just shows an Opps page.
Problem is, those hidden required fields cause a CFTHROW which in turns stops processing and shows the Opps page.
I am now tasked with letting these errors slide through the onError() event. But how?
Is there a certain type of error this produces?
Anyway, thought I would add this to the comments about Error Handling. DONT USE HIDDEN REQUIRED FIELDS. they suck!!
Tim
Comment 72 written by Tim Garver on 11 November 2008, at 4:58 PM
turns out this will catch those errors in the onError() event
<cfif Arguments.Exception.message NEQ "Form entries incomplete or invalid.">
<cfoutput>#Arguments.Exception.detail#</cfoutput>
</cfif>
This still does not solve my issue. Seems like you could put a try on the form page to catch the error, wrong. its caught by App.cfc before it hits the form action page.
So ignoring this error seems impossible at this point.
Will update if I find a solution.
Tim
Comment 73 written by Tim Garver on 11 November 2008, at 4:59 PM
This should have EQ, not NEQ
<cfif Arguments.Exception.message EQ "Form entries incomplete or invalid.">
<cfoutput>#Arguments.Exception.detail#</cfoutput>
Fill out the form dummy :D
</cfif>
Comment 74 written by Andrew Myers on 18 December 2008, at 4:28 PM
Thanks for yet another great article.
I'm using CF7 and whenever I try and log
#arguments.eventname# and #arguments.exception.message#
I get messages like this
"Error","jrpp-738","12/15/08","12:02:33","HRA_V2","Event Name: onRequest"
"Error","jrpp-738","12/15/08","12:02:33","HRA_V2","Message: Event Handler Exception."
I have found I need to look to the "Root Cause" to actually see the information you are mentioning:
<cflog file="#This.Name#" type="error" text="Template: #arguments.exception.RootCause.TagContext[1].template#">
<cflog file="#This.Name#" type="error" text="Line: #arguments.exception.RootCause.TagContext[1].line#">
<cflog file="#This.Name#" type="error" text="Message: #arguments.exception.RootCause.message#">
This produces:
"Error","jrpp-1603","12/19/08","09:18:21","HRA_V2","Template: /www/html/root/throw-error.cfm"
"Error","jrpp-1603","12/19/08","09:18:21","HRA_V2","Line: 1"
"Error","jrpp-1603","12/19/08","09:18:21","HRA_V2","Message: Variable XFHDSHSDHJ is undefined."
Curiously if I put <cfthrow object="#arguments.exception#"> in the onError function I see the real error (eg. Variable XFHDSHSDHJ is undefined), but if I <cfdump> it, it is wrapped in the "Event Handler Exception".
Any ideas? I'm confused as to why this happens to me but not anyone else? ;-)
Comment 75 written by Raymond Camden on 18 December 2008, at 4:35 PM
Comment 76 written by Andrew Myers on 18 December 2008, at 4:41 PM
Is there any problem with doing this:
arguments.exception.RootCause.TagContext[1].template
Will the exception passed into the onError() method of Application.cfc always have a RootCause, with a TagContext array of at least 1 element?
Comment 77 written by Raymond Camden on 18 December 2008, at 4:55 PM
if structkeyexists(exception, "rootcause") and structkeyexists(exception.rootcause, "tagcontext") and arraylen(exception.rootcaue.tagcontext gte 1
Comment 78 written by Dave Dugdale on 26 January 2009, at 11:11 PM
Comment 79 written by Raymond Camden on 27 January 2009, at 11:19 AM
Comment 80 written by Dave Dugdale on 27 January 2009, at 11:42 AM
Comment 81 written by Dave Dugdale on 27 January 2009, at 2:01 PM
<cffunction name="onError" returnType="void" output="true">
<cfargument name="exception" required="true">
<cfargument name="eventname" type="string" required="true">
<cfset var errortextemailonly = "">
<cfset var errortext = "">
<!--- plain error message email for IPhone --->
<cfsavecontent variable="errortextemailonly">
<cfoutput>
Error on Page: http://#cgi.server_name##cgi.script_name#/ param: #cgi.query_string#<br>
<br>
Refferal Page: #cgi.http_referer# <br>
<br>
User's IP: #cgi.REMOTE_ADDR#<br>
<br>
Server Port: #cgi.SERVER_PORT#<br>
<br>
Error Date: #dateFormat(now(), "short")# #timeFormat(now(), "short")#<br>
<br>
User's Browser: #cgi.HTTP_USER_AGENT#<br>
<br>
------------------------------------<br>
CF Error: #arguments.exception.message#<br>
</cfoutput>
</cfsavecontent>
<!--- full error message for desktop troubleshooting --->
<cfsavecontent variable="errortext">
<cfoutput>
#errortextemailonly#<br>
<cfdump var="#arguments.exception#" label="Error">
<cfdump var="#form#" label="Form">
<cfdump var="#url#" label="URL">
</cfoutput>
</cfsavecontent>
<cfif Application.emailErrorMessaging EQ "on">
<cfmail
to="dave@#Application.widgetURL#"
from="#Application.coname# <dave@#Application.widgetURL#>"
subject="Error #Application.coname# #arguments.exception.message#"
type="html"
server="#Application.mailServer#">
#errortextemailonly#
</cfmail>
</cfif>
<cfif #REMOTE_ADDR# NEQ #Application.davesIP#>
<!--- Show visitors the nicely formatted error --->
<cflocation url="exceptions/error_exception.cfm" addtoken="no">
<!--- Show me the full error for the desktop --->
<cfelse>
<cfoutput>#errortext#</cfoutput>
</cfif>
</cffunction>
Comment 82 written by Balaji on 23 February 2009, at 11:50 AM
We have on missing template handler in CF7 and CF8 and we can call in the Applicaiton.cfc file.But how can we handle the missing template error in CF earlier versions without setting up in ColdFusion administrator.
Comment 83 written by Raymond Camden on 23 February 2009, at 1:58 PM
Comment 84 written by Tim Garver on 23 February 2009, at 2:54 PM
it will work in IIS as Ray points out, also in Apache as well, but you can forgot it if you want to do url rewrite with either of these webservers
Comment 85 written by Raymond Camden on 23 February 2009, at 2:56 PM
Comment 86 written by Tim Garver on 23 February 2009, at 3:02 PM
the web server itself with do an internal redirect to the 404 page.
for plain error catching using a custom 404, it will work just fine.
Comment 87 written by Raymond Camden on 23 February 2009, at 3:05 PM
Comment 88 written by Rob Barthle on 26 February 2009, at 9:33 AM
The error handlers work, we get enough usage out of them to know that. There are times though that an error is not caught by our handlers, and gets caught by the site wide error handler.
My boss doesn't believe any error should ever make it that far, and all errors need to get caught and handled by our error handlers regardless of their cause. I believe he is being unrealistic about that, that there are some errors that just cannot be trapped beforehand and that is why the site wide error handler is there. But I need something to back up my thoughts.
I can give you a couple of examples of error messages the site wide has caught, if that is any help.
ERROR DIAGNOSTICS:String index out of range: -1 null <br>The error occurred on line -1. error.message = String index out of range: -1 error.rootCause = java.lang.StringIndexOutOfBoundsException: String index out of range: -1
ERROR DIAGNOSTICS:Session is invalid null <br>The error occurred on line 79. error.message = Session is invalid error.rootCause = java.lang.IllegalStateException: Session is invalid
ERROR DIAGNOSTICS:Operation failed on the data source named ""FREE"". Reason of failure ""java.sql.SQLException: [Macromedia][SQLServer JDBC Driver]Error establishing socket. Connection refused"" <br>The error occurred on line 96. error.message = Operation failed on the data source named ""FREE"". error.rootCause = coldfusion.runtime.ClientScopeDBException: Operation failed on the data source named ""FREE"".
Comment 89 written by Raymond Camden on 27 February 2009, at 9:50 AM
Comment 90 written by Mickey on 26 March 2009, at 1:23 PM
I'm trying to be good and implement a catch-all error handling process using application.cfc. I should also mention that I'm using Fusebox 5.5 and have called the "Super" scope accordingly where needed.
I've tried several variations using this post and other examples but I just can't seem to get detailed info emailed to me while also redirecting the user to a "pretty" page. I'm also writing errors to a log file but so far that doesn't seem to be a problem.
Currently the <cflocation> tag in the onError method of app.cfc is causing it's own forever looping exception. I can instead <cfoutput> the "pretty" message directly from app.cfc but that can leave half drawn pages and other ugly results visible. I also tried GetPageContext() using cfscript but it has the same results as <cflocation>.
I've read about setting up a check to filter "coldfusion.runtime.AbortException" but if I've read correctly that is no longer needed since 7.01 (I'm on 7.02)... either way it has no effect.
My other issue is that the most common errors I'm testing for seem to miss the onError method completely. I can trap them by placing a <cferror type="request" template="Error.cfm"> in the OnRequestStart method, but then I'm limited to how I can format the error page and I can't email the error to myself (as pointed out above). I may just have to accept that but it's worth asking if there might be a better alternative... especially since it seems this may catch more than onError. Would a Try/Catch in OnRequestStart give me more options... or just shoot me in the foot?
Any ideas, clarifications or updates would be very much appreciated.
Comment 91 written by Raymond Camden on 26 March 2009, at 9:04 PM
Comment 92 written by Mickey on 27 March 2009, at 11:30 AM
Anyway, I had the cflocation inside the onError method as in your example. To test, I was forcing an exception and seeing the exception error looping in my log file. I now find that the loop has nothing to do with exceptions. It's tied to cflocation.
I took out all of the onError stuff I was trying and then added some <cflog> tags to the methods in application.cfc. Then I just added a cflocation to one of my pages. It still loops but doesn't hit onError. I can see where new requests and sessions are being generated several times per second but never finishing. Fusebox is also reinitialized as part of the loop.
I have two identical files that I've tried to cflocate to. They are very basic and identical except one is named error.cfm and the other is error.htm. You are right that the htm file works just fine though I'm not sure what that tells me. Oh and I can also cflocate to an exernal url like "http://www.google.com" with no problem.
I suspect I'm just missing something in relation to launching fusebox 5.5 using application.cfc while also trying to do some other creative things with application.cfc. But hey, that's how we learn. If I never broke anything I wouldn't know how to fix anything.
Comment 93 written by Russ on 23 April 2009, at 4:25 AM
I've developed a solution that stores errors as JSON data in a database. I only store the most recent 100 errors so that if a major glitch happens while I'm asleep it won't clog the database. When an error occurs, I send an email that only contains a basic message with the template and line number, and a link to my "error admin" which displays the verbose error data (that I stored as JSON) using cfdump.
Storing errors in a database lets me flag things that are fixed and things that are not using my "error admin", which is quite handy when I am procrastinating.
Comment 94 written by Russ on 23 April 2009, at 4:28 AM
Comment 95 written by Lee Crockett on 24 April 2009, at 10:20 AM
http://infosavvygroup.com/bugreport_request.cfm
Comment 96 written by Doug on 27 April 2009, at 1:11 PM
Anyone notice that when the request error runs (and possibly the other errors too) it puts the error message into the http response header? Is there any way to hide it there so all it shows is a generic 500 error instead of mentioning whatever is going wrong in my code?
Comment 97 written by Raymond Camden on 27 April 2009, at 1:18 PM
Comment 98 written by Doug on 27 April 2009, at 1:26 PM
Comment 99 written by Raymond Camden on 27 April 2009, at 1:27 PM
Comment 100 written by Doug on 27 April 2009, at 1:36 PM
...Speaking of "never too much paranoia", didn't Adobe recently give an update to get ColdFusion to read .htm files like .cfm files? Talk about catering to the paranoid. :D
Comment 101 written by Raymond Camden on 27 April 2009, at 2:32 PM
Are you saying you have an error handler, it says something simple "Oops", and yet you can still sniff out the underlying error? (ie, db, bad variable, etc)
Comment 102 written by Doug on 27 April 2009, at 3:02 PM
I never got around to defining a mail server on my development server, mostly due to procrastination. So when I created "test.cfm" the error.cfm threw an error because of the cfmail tag which then led to the error_request.cfm. When I then checked the HTTP header on the error_request.cfm I got this: "500 No SMTP server specified for the cfmail tag."
Perhaps it's because it's an error caused by my failure to setup the SMTP server or because it's the error_request template. Maybe?
Comment 103 written by Raymond Camden on 27 April 2009, at 3:10 PM
500 Internal Server Error
Nice and vague.
Comment 104 written by Doug on 27 April 2009, at 3:20 PM
Comment 105 written by Raymond Camden on 27 April 2009, at 3:22 PM
Comment 106 written by Jems on 15 May 2009, at 2:41 PM
I have spoiled my one day to practice the Coldfusion Validations and I couldnt pass this guy. validateAt is not working for 'onsubmit' or 'blur', working perfectly for 'onserver'.
here is my code
----------------
<html>
<head></head>
<body>
<cfform action="insert2.cfm" method="post">
Enter a Number:
<cfinput type="text" name="ValNumber" maxlength="3" required="yes" validate="integer" validateat="onsubmit">
<cfinput type="submit" name="submit" value="submit">
</cfform>
</body>
</html>
Any help is highly appreciated, thanks
Jems.
Comment 107 written by Rob on 15 May 2009, at 3:48 PM
Comment 108 written by Don on 26 May 2009, at 1:22 PM
[Application.cfc]
<cffunction name="onError">
<cfargument name="Exception" required=true/>
<cfargument type="String" name="EventName" required=true/>
<cfif NOT (Arguments.EventName IS "onSessionEnd") OR (Arguments.EventName IS "onApplicationEnd")>
<cfinclude template="includes/dsp_allErrors.cfm">
</cfif>
</cffunction>
[dsp_allErrors.cfm]
<cfsavecontent variable="theError"> #arguments.exception.message#
#arguments.exception.detail#
#arguments.exception.tagContext[1].template# LINE #arguments.exception.tagContext[1].line# <cfif ISDEFINED("arguments.exception.sql")>
#arguments.exception.sql#
</cfif>
</cfsavecontent>
<cflog file="AppErrorLog" type="error" text="#theError#">
I just pull the info out that I need instead of doing a full dump. How many acutally use the stack dumps etc? I haven't used a stack dump since my machine language days (which is back when we had to slide beads around on a framework)
Of course the user only sees "YOU BROKE IT YOU MORON!" message and I get the email telling me to check the log.
Comment 109 written by Jody Fitzpatrick on 9 August 2009, at 3:23 PM
occured due to the server side process. But if a user
caused the error I would tell them. eg.) Invalid Email or something, but truthfully that really isn't an error it's just aninvalid input. I hope you guys understand what I'm talking about
Comment 110 written by Lance Caetan on 28 August 2009, at 9:28 AM
http://www.adobe.com/support/security/bulletins/ap...
Please Advise.
Comment 111 written by Raymond Camden on 28 August 2009, at 9:54 AM
Comment 112 written by Lance Caetan on 28 August 2009, at 10:37 AM
Comment 113 written by Raymond Camden on 28 August 2009, at 12:40 PM
Comment 114 written by Lance Caetan on 28 August 2009, at 2:35 PM
Comment 115 written by Raymond Camden on 29 August 2009, at 10:01 PM
Comment 116 written by Paul Dynan on 11 September 2009, at 12:05 PM
I ask because we have a few hundred sites on two servers (CF v7 & 8). That means not only a mix of applicaiton cfc and cfm sites, but modifying all of the, and adding the error pages to each.
It seems like the site-wide option would be great in our case, but if there's a good/wise reason not to, I have no problem putting in the time to fix these individually if necessary.
Also, if we do it per-site, is it worth putting all of the error handing into a cfc for all the error pages to call? It seems like that at least would make ongoing management easier, but I wasn't sure if the nature of the error pages restricted that.
Comment 117 written by Raymond Camden on 11 September 2009, at 12:29 PM
As to your second question - by 'all the error handling' - do you mean what to do with the exception info? Obviously you can't put onError in it's own CFC. It needs to be in App.cfc. I guess I'd say - if you are doing a -lot- with the errors, then maybe so. I typically just dump and mail (2 lines or so) so a CFC would be overkill.
Comment 118 written by Paul Dynan on 11 September 2009, at 12:53 PM
The second point was just trying to find a way manage all of the handling for the individual error pages from a single page. My idea would be to have all the error.cfm pages call a shared error.cfc, which in turn would do all of the handling.
Ultimately, I'd like to have the error info inserted into a database, instead of mailed (too many sites, multiple people administering, etc). This way, the error page could say "when contacting support, refer to error #1257", which would be the ID in the database where that error is held. It would also allow us to hold the dump in its entirety if we like.
Obviously, there may be adjustments that may need to be done along the way, so I just want to make adjustments to one cfm or cfc page that would have the code doing this, to avoid updating all of the error pages individually.
Comment 119 written by Raymond Camden on 11 September 2009, at 12:54 PM
So based on what you said - I think it _would_ make sense to abstract your error handling as you have described.
Comment 120 written by Paul Dynan on 17 September 2009, at 9:02 AM
One last question: Is there a way to alter the Error scope? I wanted to trim out the StackTrace sections or just clear the contents. We don't use them, and it would make reading the rest of the dump much easier. I have tried StructDelete and StructUpdate, but the former throws an error, and the latter just does nothing.
Comment 121 written by Raymond Camden on 17 September 2009, at 9:03 AM
Comment 122 written by Raymond Camden on 17 September 2009, at 9:10 AM
Comment 123 written by Paul Dynan on 17 September 2009, at 9:26 AM
I tried StructCopy, but it is not supported for the Error structure (much like StructDelete). Duplicate works, but still cannot be altered.
I assume you mean by looping it, but I couldn't figure out how to do that when the structure of the Error var is dynamic depending on the error.
Comment 124 written by Raymond Camden on 17 September 2009, at 9:27 AM
http://www.coldfusionjedi.com/index.cfm/2009/9/17/...
Comment 125 written by Brad on 18 September 2009, at 6:17 PM
cheers!
[Add Comment] [Subscribe to Comments]