CFCATCH throwing error in CFC - coldfusion

For some reason, a piece of code that works fine on a *.cfm page, and did work fine in a *.cfc, now is throwing an error when error is detected.
The error is:
Element SQL is undefined in CFCATCH.
The code block where this is getting throw looks like this:
<cfcatch type="database">
<cfset errorMessage = "
<p>#cfcatch.message#</p>
<p>Please send the following to a developer:</p>
<p>#cfcatch.SQL#</p> <--- ERROR HERE
<p>#cfcatch.queryError#</p>
<p>#cfcatch.Where#</p>">
some other stuff
</cfcatch>
Any thoughts?
UPDATE
Using #BenKoshy suggestion, I modified my <cfcatch> statement.
Remember K.I.S.S.? Keep It Simple Stupid
Using his method and then modifying it, I was getting more data back than I was going use, so I went with a simple version, and it works as advertised.
<cfif isDefined("cfcatch.message")>
<cfset errorMessage = errorMessage & "<p>#cfcatch.message#</p>">
</cfif>
<cfif isDefined("cfcatch.SQL")>
<cfset errorMessage = errorMessage & "<p>Please send the following to a developer:</p><p>#cfcatch.SQL#</p>">
</cfif>
<cfif isDefined("cfcatch.QueryError")>
<cfset errorMessage = errorMessage & "<p>#cfcatch.queryError#</p>">
</cfif>
<cfif isDefined("cfcatch.Where")>
<cfset errorMessage = errorMessage & "<p>#cfcatch.Where#</p>">
</cfif>
Nice and easy and it works. KISS

Just means the error data did not contain an SQL statement. Shouldn't assume that variable will exist for all errors:
<cfif isDefined("cfcatch.sql")>
<p>#cfcatch.SQL#</p>
</cfif>
Is the easy fix. Probably best to loop through the struct like this:
<cfparam name="errorMessage" default="">
<cfloop collection="#cfcatch#" item="this">
<cfset errorMessage = errorMessage & "<p>#cfcatch[this]#</p>">
</cfloop>

Related

Coldfusion exception not caught by containing try/catch

You can run this cftry gist with either the first or second indicated block of code uncommented to see the problem.
<cffunction name="alpha" returntype="boolean">
<cfargument name="boo" type="boolean" />
<cfreturn arguments.boo />
</cffunction>
<cffunction name="beta">
<cfset var temp = {} />
<cftry>
<cfset temp.userID = 1 />
<!--- This way throws an *unhandled* exception --->
<!--- --->
<cfif alpha(structAppend({userID = temp.userID}, foo))>
<cfdump var="It worked" />
</cfif>
<!--- This way works as expected --->
<!---
<cfset temp.args = {userID = temp.userID} />
<cfif alpha(structAppend(temp.args, foo))>
<cfdump var="It worked" />
</cfif>
--->
<cfcatch>
<cfdump var="#cfcatch.message#" />
</cfcatch>
</cftry>
</cffunction>
I know the struct literal notation {} will sometimes show generically named structs in my debugger, but why should assigning what's created by such syntax make the struct creation happen at a different time than if it's not assigned?
If I debug, I can set a breakpoint on the line where I set temp.userID = 1 and it skips right over it. Moreover, the exception is being thrown on a line contained in a try/catch, but it's failing to catch it.
I know in JavaScript there's the notion of 'hoisting'. I can only assume in some (but not all!) cases CF is doing something similar to struct literals.
Is this a bug, or a known behavior of CF?

Catching an error message

I'm using Coldfusion Fusebox 3 and I would like to know how I can keep my app from throwing an error message if someone thoughtlessly removes the Circuit and fuseaction from the URL.
For example, if the original URL is:
http://www.noname/Intranet/index.cfm?fuseaction=Bulletins.main
...and someone removes the circuit information so it reads like the following: http://www.noname/Intranet/index.cfm?fuseaction=
...the app throws an error message. Can I code against something like this happening?
Here is my fbx_Settings.cfm file as it exists right now. Thank you.
Try something along these lines, haven't had chance to test but should go something like this in your index.cfm file.
<cfprocessingdirective suppressWhiteSpace="yes">
<cftry>
<!--- Include the config file --->
<cfinclude template="../config.cfm">
<cfset variables.fromFusebox = True>
<cfinclude template="fbx_fusebox30_CF50.cfm">
<cfif Len(fusebox.fuseaction) EQ 0>
<!--- Error Handle --->
</cfif>
<cfcatch type="Any">
<!---<cfset SendErrorEmail("Error", cfcatch)><cfabort />--->
</cfcatch>
</cftry>
</cfprocessingdirective>
or better still, in your switch file have a default case such as:
<cfdefaultcase>
<cfinclude template="act_HandleError.cfm">
<cflocation url="hompage.cfm" addtoken="false">
</cfdefaultcase>
Hope this helps!

Error with undefined variables while looping over a query

I have an error while looping over a query using cfloop.
When I use a cfdump on the query (inside the loop, mind you), I can see all the data just fine. But when I try to get the value of each variable as you normally do in cfloop, I get a message that says they are undefined. I then changed each variable to reference the query specifically, and now the problem is that the variable is undefined in the query. Here's the code:
<cffunction name="writeCourses">
<cfargument name="recordset" required="yes" type="query">
<cfif recordset.RecordCount NEQ 0>
<cfset temp = "">
<cfoutput>
<cfloop query="recordset">
<!--- <cfdump var="#recordset#"> <cfabort/> --->
<cfset temp = temp & "<strong>#recordset.courseType# #recordset.courseNum# ">
<cfif isDefined("recordset.courseTHM") AND recordset.courseTHM EQ 1>
<cfset temp = temp & "(#left(recordset.courseNum,3)#4) ">
</cfif>
<cfif isDefined("recordset.courseName")>
<cfset temp = temp & "#recordset.courseName# </strong><br>">
</cfif>
<cfset temp = temp & "#recordset.courseDESC#<br>">
<cfset temp = temp & "#recordset.courseHours#<br><br>">
</cfloop>
</cfoutput>
<cfelse>
<cfset temp = "">
</cfif>
<cfreturn temp>
</cffunction>
So as you can see, each variable is enclosed in ## tags. Originally none of them were proceeded by recordset. but they were still undefined. And when I uncomment the cfdump and cfabort tags, those work fine and I can see the recordset query with all the data as it should be.
Every other time I have used cfloop with a query it works as expected. Also, I did not write this code, I am having to modify it (the original author no longer works here).
Here's an example of the recordset dump:
The error message:
Detail: [empty string]
ErrNumber: 0
Message: Element COURSETYPE is undefined in RECORDSET.
Resolvedname: RECORDSET
The error line is:
<cfset temp = temp & "<strong>#recordset.courseType# #recordset.courseNum# ">
<cfif isDefined("recordset.courseTHM") AND recordset.courseTHM EQ 1>
<cfset temp = temp & "(#left(recordset.courseNum,3)#4) ">
</cfif>
<cfif isDefined("recordset.courseName")>
<cfset temp = temp & "#recordset.courseName# </strong><br>">
</cfif>
That's all one line :/
The stored procedure/function calling the above:
<cffunction name="getCoursesByDept">
<cfargument name="deptCode" required="yes" type="string">
<CFSTOREDPROC procedure="dbo.GetCourses" datasource="WebCatalog">
<CFPROCPARAM type="IN" dbvarname="#deptCode" value="#deptCode#" cfsqltype="CF_SQL_CHAR">
<CFPROCRESULT name="result">
</CFSTOREDPROC>
<cfinvoke method="writeCourses" recordset="#result#" returnvariable="output">
<cfreturn output>
</cffunction>
Your problem appears to be failure to scope. Here are your first 4 lines:
<cffunction name="writeCourses">
<cfargument name="recordset" required="yes" type="query">
<cfif recordset.RecordCount NEQ 0>
<cfset temp = "">
Try it like this:
<cffunction name="writeCourses">
<cfargument name="recordset" required="yes" type="query">
<cfset var temp = "">
<cfif arguments.recordset.RecordCount NEQ 0>
The differences are the use of the var keyword for your local variable temp, and adding the arguments scope to the recordset variable.
(In addition to Dan's comments ...)
If [the procedure] can't find anything it returns a query containing
an error message (i.e. no course found)
Then that means the COURSETYPE column does not always exist in the resultset, which is exactly what the error message is reporting. If the procedure returns any result, regardless of the contents, the code inside the cfif block will execute. Since the first line of code uses that column, without verifying it exists, it would cause the exact error you are seeing.
Also, as I mentioned in the comments, you really need to localize the function variables result, output, temp, etectera. Lack of var scoping can create problems, even within same page, if you reuse variable names. As #Dan suggested you should fully scope all variables - in particular, the function arguments.
(As an aside, I understand you are modifying existing code, but the error message should really be handled in CF, not inside the procedure. The procedure's job is just to return data. The CF code should check the recordCount and take the appropriate action if no records are found.)

why can I not catch an error message in a Coldfusion cftry/cfcatch statement?

I have a form where I can upload logos a plenty. I'm validating files (empty form fields, wrong extension, ...) inside a cftry/cfcatch statement.
When I find an error in the cftry, I do this:
<cfthrow type="FileNotFound" message="#tx_settings_app_error_create_first#" />
and inside my 'cfcatch'
<cfcatch>
<cfoutput><script type="text/javascript">window.onload = function(){alert("#cfcatch.message#");window.location.href="hs_apps.cfm"; } </script></cfoutput>
</cfcatch>
This works fine, catches all errors and alerts the user what is wrong.
Now I wanted to use the same handler on a database call where I'm checking for duplicate username. Still the same:
<cfquery datasource="#Session.datasource#" name="duplicates">
SELECT a.app_alias
FROM apps AS a
WHERE a.iln = <cfqueryparam value = "#Session.loginID#" cfsqltype="cf_sql_varchar" maxlength="13">
AND a.app_alias = <cfqueryparam value = "#form.app_basic_alias#" cfsqltype="cf_sql_varchar" maxlength="50">
</cfquery>
<cfif duplicates.recordcount GT 0>
<cfthrow type="FileNotFound" message="#tx_settings_apps_error_dup#" />
</cfif>
The cfcatch is also the same.
However. This now procudes a server error page and I'm thrown out of the application.
Question:
Any idea, why I'm struggling to get cftry/cfcatch to work here? I'm clueless.
Thanks!
EDIT:
Here is the full code
<cfif isDefined("send_basic")>
<cfset variables.timestamp = now()>
<cfset variables.orderview = "1">
<cfif form.send_basic_type EQ "new">
<cftry>
<cfif module_check.recordcount GT 0>
<cfloop query="module_check">
<cfif module_check.module_name EQ "preorder">
<cfset variables.module_name = module_check.module_name>
<cfset variables.b2b_preord_ok = "true">
</cfif>
</cfloop>
<cfif form.app_basic_orderview EQ "preo">
<cfset variables.orderview = "0">
</cfif>
</cfif>
<!--- PROBLEM HERE: DUPLICATES --->
<cfquery datasource="#Session.datasource#" name="duplicates">
SELECT a.app_alias
FROM apps AS a
WHERE a.iln = <cfqueryparam value = "#Session.loginID#" cfsqltype="cf_sql_varchar" maxlength="13">
AND a.app_alias = <cfqueryparam value = "#form.app_basic_alias#" cfsqltype="cf_sql_varchar" maxlength="50">
</cfquery>
<cfif duplicates.recordcount GT 0>
<cfthrow type="FileNotFound" message="#tx_settings_apps_error_dup#" />
</cfif>
<!--- IF PASS, CREATE/UPDATE --->
<cfquery datasource="#Session.datasource#">
INSERT INTO apps ( ... )
VALUES( ... )
</cfquery>
<cfset variables.app_action = "Applikation erstellt">
<!--- success --->
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_app_cfm_create#");}</script></cfoutput>
<cfcatch>
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_app_err_create#");}</script></cfoutput>
</cfcatch>
</cftry>
<cfelse>
<cftry>
<!--- UPDATE --->
<cfquery datasource="#Session.datasource#">
UPDATE apps
SET ... = ...
</cfquery>
<cfset variables.app_action = "Applikation aktualisiert">
<!--- success --->
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_app_cfm_update#");}</script></cfoutput>
<cfcatch>
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_app_err_update#");}</script></cfoutput>
</cfcatch>
</cftry>
</cfif>
</cfif>
The error message I'm getting it the message I specify =
<cfthrow type="FileNotFound" message="#tx_settings_apps_error_dup#" />
Which if caught should alert the text behind tx_settings_apps_error_dup. If I dump the cfcatch, cfcatch.message is my specified text, so the error gets caught allright, only I get a server error page vs. an alert. I'm using exactly the same handler for fileuploads and form submits. I don't get why it's not working here?
Thanks for helping out!
WORKAROUD:
Note nice, but suffice(s):
<cfif dups.recordcount NEQ 0>
<cfoutput><script type="text/javascript">window.onload = function(){alert("#tx_settings_apps_error_dup#"); location.href = "hs_apps_detail.cfm?create=newApp&id=none";}</script
</cfoutput>
<cfabort>
</cfif>
So when a duplicate is found I alert the user, reload the exact same page and cfabort to prevent the old page from processing further. Patch that is.
(moved this down from being just a comment)
OK, so the catch is definitely catching the exception if you're able to dump it, so it's not that the try/catch ain't working, it's something else. Bear in mind that processing will continue until the end of the request after your catch block, and only then will the output buffer be flushed, and your alert() sent to the browser. It sounds to me like after your output the alert, and processing continues, some OTHER error is occurring which is causing the server's error page to display. I recommend getting rid of the error page temporarily and eyeballing the actual error CF is raising.
NB: if you want processing to stop immediately in the catch block after you output the alert(), you're going to need to tell CF that, ie: with a <cfabort>. Otherwise, as per above, it'll just keep going.
I think exceptions that are caught by the server error page are still logged in the exception log, but I could be wrong. You could always put an onError() handler in your Application.cfc, log whatever error occurred, then rethrow the error so the error page still deals with it. That way you get the info on the error, and the punter still sees the nice error page.

ColdFusion = OnRequest Error

Looking through the logs, we're getting hundreds of the following
"Error","jrpp-185","08/21/12","10:05:43","PATH","www.domain.com
Agent:Mozilla/4.0 (compatible; Synapse)
Error: An exception occurred when invoking a event handler method from Application.cfc.
The method name is: onRequest.
They seem to be mostly search bots. The on place on APplication.cfc that I can see reference to the function is below
<cffunction name="onRequest" returnType="void">
<cfargument name="targetPage" type="String" required=true/>
<cfsetting enablecfoutputonly="yes" requesttimeout="20">
<cfparam name="url.refresh" default="0">
<cfset request.strMember = Duplicate(session.strMember)/>
<cfset request.tNow = GetTickCount()>
<cfif url.refresh EQ 0>
<cfset request.iCacheHr = 12/>
<cfelse>
<cfset request.iCacheHr = 0/>
</cfif>
<cflogin>
<cfif IsDefined("session.strMember.sRoles")>
<cfloginuser name="#session.strMember.sFirstName##session.strMember.sLastName#"
password="12345"
roles="#session.strMember.sRoles#"/>
</cfif>
</cflogin>
<cfinclude template="core/incl/SessionLogger.cfm">
<cfinclude template="core/incl/LinkTranslator.cfm">
<cfinclude template="core/incl/udf.cfm">
<cfinclude template="urlcheck.cfm"/>
<cfinclude template="#Arguments.targetPage#">
</cffunction>
From that, can anyone please advise on what's wrong and how to fix it? I'm fairly new to CF and this is making me pull out what little hair I have left
1) You use two different coding styles
<cfparam name="url.refresh" default="0">
<cfset request.strMember = Duplicate(session.strMember)/>
Invalid/left open XML tags in first line and valid (closed) XML tags in the second line.
Try to stick to one (preferably the last one).
2) You are using old way of checking variable being defined
IsDefined("session.strMember.sRoles")
read about newer (and better and faster)
StructKeyExists(session.strMember, "sRoles")
3) Most likely your code is calling
<cfloginuser ... >
at every page request
4) Make sure that paths for all includes are correct and they themselves don't have any errors.
Simplify your method until you stop getting an error and then investigate what exactly is causing it
Are the bots hitting a page that doesn't exist?
Maybe try changing the last line to:
<cfif fileExists(expandPath(Arguments.targetPage))>
<cfinclude template="#Arguments.targetPage#">
<cfelse>
<cfabort>
</cfif>
Maybe you could detect if they are a bot and server them something else? depends on how search friendly you want your site to be:
http://www.bennadel.com/blog/1083-ColdFusion-Session-Management-And-Spiders-Bots.htm