[Coldbox 6.6.1] Unable to intercept application error

Hello,

we are experiencing a quite mysterious problem with our application when it is in production. It complains for lack of required params (which are actually passed) or of methods (i.e. Class has no method named “search” while it actually has it).

Usually, once the server is restarted all works fine but we would like to get to the root of this problem so that we can understand why and how it happens. In order to do this, we would like to be able to log the entire error stacktrace.

And here comes the complicated part.

Below is our configure function in Coldbox.cfc

function configure() {
 coldbox = {
     ....other keys,
    exceptionHandler : "UtilController.onError"
  }
}

Unfortunately, we see that when there is an Application Error the UtilController does not get called.
Moreover, we have added a onError function in our Application.cfc and still it does not get called.

In our MainInterceptor we can access prc.cbox_rendedata.DATA but the problem is that it contains only some details of the error while we need the entire stacktrace.

Cattura

To sum up, not our UtilController nor our Application.cfc’s onError method are able to intercept the application error and show its stacktrace. Our MainInterceptor can access prc but, still, can access only a small portion of the error not useful for what we are trying to achieve.

What are we missing? Hope I’ve been clear. Otherwise feel free to ask me for any kind of clarification.

Thank you really much for the attention

Can you post your util cpmtroller?
Are you using the rest handler?
If so have you checked logs?
Are you using logbox in your coldbox configuration?

This is our UtilController

component extends="AbsController" {

	function index( event, rc, prc ) {

		echo( "Default route, or route not specified" );

		cfheader( statuscode="400", statustext="Route not specified" );

		abort;
	}

	function onError( event, rc, prc ) {

		dump( arguments.prc.exception.getExceptionStruct() );

		cfheader( statuscode="500", statustext="Application error" );
 
		echo( "Error 500" );
		abort;

	}

	function echo( event, rc, prc ) {	

		param name="url.name" default="NAME-NOT-SET";

		dump( var=url, label="URL SCOPE" );
		dump("rc.name: #rc.name#");
		abort;

	}

}

All controllers extend the AbsController which in turn extends the RestHandler.
I’ve checked the logs in server.out.txt and they contain the stacktrace and we are not using logbox.

The logs contain the following stacktrace

lucee.runtime.exp.ExpressionException: Component [views.api.controller.UserController] has no accessible Member with name [CLIPSV]
lucee.runtime.ComponentScopeShadow.get(ComponentScopeShadow.java:130)
views.api.controller.usercontroller_cfc$cf$2.udfCall(/views/api/controller/UserController.cfc:14)
lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:106)
lucee.runtime.type.UDFImpl._call(UDFImpl.java:344)
lucee.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:207)
lucee.runtime.type.scope.ArgumentImpl.callWithNamedValues(ArgumentImpl.java:518)
lucee.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:866)
lucee.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1766)
system.resthandler_cfc$cf.udfCall1(/coldbox/system/RestHandler.cfc:58)
system.resthandler_cfc$cf.udfCall(/coldbox/system/RestHandler.cfc)
lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:106)
lucee.runtime.type.UDFImpl._call(UDFImpl.java:344)
lucee.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:207)
lucee.runtime.ComponentImpl._call(ComponentImpl.java:685)
lucee.runtime.ComponentImpl._call(ComponentImpl.java:572)
lucee.runtime.ComponentImpl.callWithNamedValues(ComponentImpl.java:1930)
lucee.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:866)
lucee.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1766)
system.web.controller_cfc$cf.udfCall3(/coldbox/system/web/Controller.cfc:946)
system.web.controller_cfc$cf.udfCall(/coldbox/system/web/Controller.cfc)
lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:106)
lucee.runtime.type.UDFImpl._call(UDFImpl.java:344)
lucee.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:207)
lucee.runtime.type.scope.UndefinedImpl.callWithNamedValues(UndefinedImpl.java:802)
lucee.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:866)
lucee.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1766)
system.web.controller_cfc$cf.udfCall3(/coldbox/system/web/Controller.cfc:667)
system.web.controller_cfc$cf.udfCall(/coldbox/system/web/Controller.cfc)
lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:106)
lucee.runtime.type.UDFImpl._call(UDFImpl.java:344)
lucee.runtime.type.UDFImpl.callWithNamedValues(UDFImpl.java:207)
lucee.runtime.ComponentImpl._call(ComponentImpl.java:685)
lucee.runtime.ComponentImpl._call(ComponentImpl.java:572)
lucee.runtime.ComponentImpl.callWithNamedValues(ComponentImpl.java:1930)
lucee.runtime.util.VariableUtilImpl.callFunctionWithNamedValues(VariableUtilImpl.java:866)
lucee.runtime.PageContextImpl.getFunctionWithNamedValues(PageContextImpl.java:1766)
system.bootstrap_cfc$cf.udfCall1(/coldbox/system/Bootstrap.cfc:285)
system.bootstrap_cfc$cf.udfCall(/coldbox/system/Bootstrap.cfc)
lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:106)
lucee.runtime.type.UDFImpl._call(UDFImpl.java:344)
lucee.runtime.type.UDFImpl.call(UDFImpl.java:217)
lucee.runtime.type.scope.UndefinedImpl.call(UndefinedImpl.java:785)
lucee.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:787)
lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:1747)
system.bootstrap_cfc$cf.udfCall1(/coldbox/system/Bootstrap.cfc:519)
system.bootstrap_cfc$cf.udfCall(/coldbox/system/Bootstrap.cfc)
lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:106)
lucee.runtime.type.UDFImpl._call(UDFImpl.java:344)
lucee.runtime.type.UDFImpl.call(UDFImpl.java:217)
lucee.runtime.ComponentImpl._call(ComponentImpl.java:684)
lucee.runtime.ComponentImpl._call(ComponentImpl.java:572)
lucee.runtime.ComponentImpl.call(ComponentImpl.java:1911)
lucee.runtime.util.VariableUtilImpl.callFunctionWithoutNamedValues(VariableUtilImpl.java:787)
lucee.runtime.PageContextImpl.getFunction(PageContextImpl.java:1747)
views.api.application_cfc$cf.udfCall(/views/api/Application.cfc:36)
lucee.runtime.type.UDFImpl.implementation(UDFImpl.java:106)
lucee.runtime.type.UDFImpl._call(UDFImpl.java:344)
lucee.runtime.type.UDFImpl.call(UDFImpl.java:217)
lucee.runtime.ComponentImpl._call(ComponentImpl.java:684)
lucee.runtime.ComponentImpl._call(ComponentImpl.java:572)
lucee.runtime.ComponentImpl.call(ComponentImpl.java:1911)
lucee.runtime.listener.ModernAppListener.call(ModernAppListener.java:437)
lucee.runtime.listener.ModernAppListener._onRequest(ModernAppListener.java:133)
lucee.runtime.listener.MixedAppListener.onRequest(MixedAppListener.java:44)
lucee.runtime.PageContextImpl.execute(PageContextImpl.java:2460)
lucee.runtime.PageContextImpl._execute(PageContextImpl.java:2450)
lucee.runtime.PageContextImpl.executeCFML(PageContextImpl.java:2421)
lucee.runtime.engine.Request.exe(Request.java:45)
lucee.runtime.engine.CFMLEngineImpl._service(CFMLEngineImpl.java:1179)
lucee.runtime.engine.CFMLEngineImpl.serviceCFML(CFMLEngineImpl.java:1125)
lucee.loader.engine.CFMLEngineWrapper.serviceCFML(CFMLEngineWrapper.java:97)
lucee.loader.servlet.CFMLServlet.service(CFMLServlet.java:51)
javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
org.cfmlprojects.regexpathinfofilter.RegexPathInfoFilter.doFilter(RegexPathInfoFilter.java:47)
io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:251)
io.undertow.servlet.handlers.ServletInitialHandler.dispatchToPath(ServletInitialHandler.java:186)
io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:227)
io.undertow.servlet.spec.RequestDispatcherImpl.forwardImplSetup(RequestDispatcherImpl.java:149)
io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:111)
org.cfmlprojects.regexpathinfofilter.RegexPathInfoFilter.doFilter(RegexPathInfoFilter.java:45)
io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:251)
io.undertow.servlet.handlers.ServletInitialHandler.dispatchToPath(ServletInitialHandler.java:186)
io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:227)
io.undertow.servlet.spec.RequestDispatcherImpl.forwardImplSetup(RequestDispatcherImpl.java:149)
io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:111)
org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:215)
org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:171)
org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:405)
io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
runwar.Server$1.handleRequest(Server.java:511)
io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:841)
org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019)
org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)
org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1449)
java.base/java.lang.Thread.run(Unknown Source)

:slight_smile:

OK, I see your issue.

All of your handlers extend the RestHandler. Thus, they are in REST mode. This means that your traditional exceptionHandler that is defined in your config/Coldbox.cfc will NOT fire. That’s because on REST calls, the aroundHandler() does a try/catch around ALL events to provide consistency on the output of the response. That’s why you are getting the response you are getting.

Cattura

There is definitely an exception in your UserController and you can see that in the stacktrace, where probably a missing dependency is there or something: UserController.cfc:14

With that said. The way the rest handler manages unhandled exceptions is that it will log the error via LogBox with a log.error call and then setup the response via the onAnyOtherException() Here is what is called:

/**
    * Action for 'any' exceptions, ie when not caught by previous catch statements
    *
    * @event          The request context
    * @rc             The rc reference
    * @prc            The prc reference
    * @eventArguments The original event arguments
    * @exception      The thrown exception
    */
function onAnyOtherException( event, rc, prc, eventArguments, exception ){
    // Log Exception
    log.error(
        "Error calling #arguments.event.getCurrentEvent()#: #arguments.exception.message# #arguments.exception.detail#",
        {
            "_stacktrace" : arguments.exception.stacktrace,
            "httpData"    : getHTTPRequestData( false )
        }
    );

    // Setup General Error Response
    arguments.prc.response
        .setError( true )
        .addMessage( "General application error: #arguments.exception.message#" )
        .setStatusCode( arguments.event.STATUS.INTERNAL_ERROR )
        .setStatusText( "General application error" );
}

If you want to change the behavior of this method, then just overwrite it in your UtilController with whatever you want :slight_smile:

Furthermore, after reading your two actions you posted I must tell you that they are untestable.

  1. Avoid the usage of dump() or echo() these are non standard approaches to producing output in the MVC world. It’s basically a brute force way to get output out.
  2. Avoid direct cfheader usage. This is untestable if you do tests or mocks. Use event.setHTTPheader() instead.
  3. Avoid abort at all costs. This actually can create AbortExceptions. If you want a graceful stop then use event.noRender(). This will stop execution gracefully. Or just set an error view to render, or return HTML from the action, or use renderData()

Finally, I have created a new ticket: [COLDBOX-1101] - Welcome

Which will allow for the RESTHandler to announce an onException() interception call whenever an exception is detected by the RESThandler.

2 Likes