Every cftry/cfcatch in the last few lessons handles exceptions where they're expected. onError, a method in Application.cfc, is the application's last line of defense: it runs whenever an exception escapes every page-level try/catch anywhere in the request, instead of falling through to ColdFusion's own default error page.
Learning Objectives
After completing this lesson, you'll be able to:
- Implement onError in Application.cfc to catch anything that escapes page-level handling.
- Read its exception and eventName parameters correctly.
- Log real diagnostic detail server-side while showing users a safe, generic message.
How onError Fits In
Exception Thrown
Any Page-Level catch Handle It?
No — onError Runs Instead
Log + Generic Error Page
onError only runs for what nothing else caught, it's a safety net, not a replacement for handling expected failures close to where they can actually happen.
A Basic Implementation
<cfcomponent>
<cffunction name="onError" returntype="void">
<cfargument name="exception" required="true">
<cfargument name="eventName" required="true" type="string">
<cflog text="Unhandled error during '#arguments.eventName#': #arguments.exception.message# — #arguments.exception.detail#" type="error">
<cfoutput><h1>Something went wrong</h1><p>We've logged the problem and are looking into it.</p></cfoutput>
</cffunction>
</cfcomponent>component {
function onError(exception, eventName) {
writeLog(
text = "Unhandled error during '#eventName#': #exception.message# — #exception.detail#",
type = "error"
);
writeOutput("<h1>Something went wrong</h1><p>We've logged the problem and are looking into it.</p>");
}
}Application.cfc can be written in either tag syntax or CFScript, same as any other component, onError behaves identically either way.
The exception and eventName Parameters
| Parameter | Meaning |
|---|---|
| exception | A structure describing what went wrong, similar to what cfcatch provides (message, detail, and the rest) |
| eventName | Which lifecycle event was running when the error happened, e.g. onRequestStart, onSessionStart, onApplicationStart, or an empty string if no onRequest method is defined |
eventName matters because an error during onApplicationStart (the application failing to initialize at all) is a very different situation from an error during a normal request, worth branching on if the two need different handling.
A Real Example: Logging Detail Without Exposing It
<cffunction name="onError" returntype="void">
<cfargument name="exception" required="true">
<cfargument name="eventName" required="true" type="string">
<cflog text="[#arguments.eventName#] #arguments.exception.type#: #arguments.exception.message# | #arguments.exception.detail#" type="error" file="application-errors">
<cfheader statuscode="500" statustext="Internal Server Error">
<cfoutput><h1>Something went wrong</h1><p>Please try again shortly.</p></cfoutput>
</cffunction>function onError(exception, eventName) {
writeLog(
text = "[#eventName#] #exception.type#: #exception.message# | #exception.detail#",
type = "error",
file = "application-errors"
);
cfheader(statuscode = 500, statustext = "Internal Server Error");
writeOutput('<h1>Something went wrong</h1><p>Please try again shortly.</p>');
}The user sees a generic, non-technical message and an appropriate HTTP status code. The full exception, including type, message, and detail, goes to a dedicated log file instead, exactly the same principle covered for cfcatch: log the real detail, never show it directly.
Common Beginner Mistakes
Treating onError as the only error handling the application needs
It's a last resort for whatever escapes every page-level try/catch. Expected failures, a failed database query, invalid user input, are still better handled specifically, close to where they happen, not left to fall all the way through to onError.
Showing the raw exception message or stack trace to the user inside onError
The same principle from cfcatch applies here: log the real diagnostic detail server-side, show the user a generic, safe message.
Ignoring eventName and assuming every call to onError happened during a normal page request
An error during onApplicationStart means the application itself failed to initialize, a fundamentally different situation from a single request failing, eventName is how onError tells the two apart.
Best Practices
- Handle expected failures with cftry/cfcatch close to where they occur, reserve onError for genuinely unhandled cases.
- Log the full exception detail (message, detail, type) to a dedicated log, never expose it directly to the user.
- Branch on eventName when a failure during application or session startup needs different handling than a failure during a normal request.
- Set an appropriate HTTP status code (like 500) from onError, rather than returning a default 200 alongside an error message.
Interview Questions
When does onError actually run?
Only when an exception escapes every page-level try/catch in the request, it's the application-wide catch-all, not the first line of defense.
What does the eventName parameter tell you, and why does it matter?
Which lifecycle event was running when the error happened (onRequestStart, onSessionStart, onApplicationStart, and so on). It matters because an application failing to start at all needs very different handling than one failed request.
Should onError show the caught exception's raw message and stack trace to the user?
No, the same principle as cfcatch applies: log the real diagnostic detail server-side, and show the user a generic, non-technical message instead.
Is onError a substitute for cftry/cfcatch around expected failure points?
No, expected failures should still be handled specifically and close to where they occur. onError exists for whatever wasn't handled anywhere else.
Summary
In this lesson, you implemented onError in Application.cfc as the application-wide catch-all for anything that escapes page-level handling, read its exception and eventName parameters, and logged real diagnostic detail server-side while keeping what the user sees generic and safe.
What's Next?
The next lesson covers cflog/writeLog specifically, recording what happened separately from whatever a user actually sees on screen.