Closed
Description
We are running flagd in NoOpProvider mode and we have defined our own CustomLoggingHook for flag evaluation. We have encountered NullPointerException while evaluation flagd in NoOpProvider mode. Ideally it should be returning default values for the flags.
Below is my CustomLogginHook.java file.
public class CustomLogginHook implements Hook<Object> {
@Override
public Optional<EvaluationContext> before(HookContext<Object> hookContext,
Map<String, Object> hookHints) {
log.debug("Flag evaluation started for key: {}", hookContext.getFlagKey());
return Optional.empty();
}
@Override
public void after(HookContext<Object> ctx, FlagEvaluationDetails<Object> details,
Map<String, Object> hints) {
log.debug("Flag evaluation completed for key: {}, result: {}", ctx.getFlagKey(), details);
}
@Override
public void error(HookContext<Object> ctx, Exception error, Map<String, Object> hints) {
log.error("Error evaluating flag: {}", ctx.getFlagKey(), error);
}
}
Error Logs:
java.lang.NullPointerException: "Cannot invoke \"dev.openfeature.sdk.HookContext.getFlagKey()\" because \"ctx\" is null"
{
"@timestamp": "2025-03-12T07:31:27.058Z",
"ecs.version": "1.2.0",
"log.level": "ERROR",
"message": "Unhandled exception when running error hook class com.amway.commerce.servicechassis.toggle.appconfigdata.flagd.hook.CustomLogginHook (only 'after' hooks should throw)",
"process.thread.name": "http-nio-8080-exec-1",
"log.logger": "dev.openfeature.sdk.HookSupport",
"IMAGE_TAG": "1.39.3",
"REQUEST_ID": "e3f457a3-4d14-9c28-a6ef-8058fcc1170c",
"act": "thvpsupp",
"spanId": "a7ab17dec04dbd8a",
"sub": "64913910",
"traceId": "b08add33b8200027369d57c8847206ec",
"error.type": "java.lang.NullPointerException",
"error.message": "Cannot invoke \"dev.openfeature.sdk.HookContext.getFlagKey()\" because \"ctx\" is null",
"error.stack_trace": [
{
"class": "com.amway.commerce.servicechassis.toggle.appconfigdata.flagd.hook.CustomLogginHook",
"method": "error",
"file": "CustomLogginHook.java",
"line": 33
},
{
"class": "dev.openfeature.sdk.HookSupport",
"method": "lambda$errorHooks$2",
"file": "HookSupport.java",
"line": 35
},
{
"class": "dev.openfeature.sdk.HookSupport",
"method": "executeChecked",
"file": "HookSupport.java",
"line": 54
},
{
"class": "dev.openfeature.sdk.HookSupport",
"method": "executeHooks",
"file": "HookSupport.java",
"line": 45
},
{
"class": "dev.openfeature.sdk.HookSupport",
"method": "errorHooks",
"file": "HookSupport.java",
"line": 35
},
{
"class": "dev.openfeature.sdk.OpenFeatureClient",
"method": "evaluateFlag",
"file": "OpenFeatureClient.java",
"line": 173
},
{
"class": "dev.openfeature.sdk.OpenFeatureClient",
"method": "getBooleanDetails",
"file": "OpenFeatureClient.java",
"line": 264
},
{
"class": "dev.openfeature.sdk.OpenFeatureClient",
"method": "getBooleanDetails",
"file": "OpenFeatureClient.java",
"line": 258
},
{
"class": "dev.openfeature.sdk.OpenFeatureClient",
"method": "getBooleanDetails",
"file": "OpenFeatureClient.java",
"line": 253
},
{
"class": "dev.openfeature.sdk.OpenFeatureClient",
"method": "getBooleanValue",
"file": "OpenFeatureClient.java",
"line": 237
},
{
"class": "com.amway.commerce.cartbizservice.app.feature.impl.FeatureServiceImpl",
"method": "getBooleanValue",
"file": "FeatureServiceImpl.java",
"line": 27
},
{
"class": "com.amway.commerce.cartbizservice.app.service.impl.CartServiceImpl",
"method": "updateCartBySubCartId",
"file": "CartServiceImpl.java",
"line": 492
},
{
"class": "com.amway.commerce.cartbizservice.app.controllers.CartController",
"method": "updateCartBySubCartId",
"file": "CartController.java",
"line": 193
},
{
"class": "jdk.internal.reflect.GeneratedMethodAccessor1259",
"method": "invoke",
"file": null,
"line": -1
},
{
"class": "jdk.internal.reflect.DelegatingMethodAccessorImpl",
"method": "invoke",
"file": "DelegatingMethodAccessorImpl.java",
"line": 43
},
{
"class": "java.lang.reflect.Method",
"method": "invoke",
"file": "Method.java",
"line": 569
},
{
"class": "org.springframework.aop.support.AopUtils",
"method": "invokeJoinpointUsingReflection",
"file": "AopUtils.java",
"line": 355
},
{
"class": "org.springframework.aop.framework.ReflectiveMethodInvocation",
"method": "invokeJoinpoint",
"file": "ReflectiveMethodInvocation.java",
"line": 196
},
{
"class": "org.springframework.aop.framework.ReflectiveMethodInvocation",
"method": "proceed",
"file": "ReflectiveMethodInvocation.java",
"line": 163
},
{
"class": "org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation",
"method": "proceed",
"file": "CglibAopProxy.java",
"line": 768
},
{
"class": "org.springframework.validation.beanvalidation.MethodValidationInterceptor",
"method": "invoke",
"file": "MethodValidationInterceptor.java",
"line": 174
},
{
"class": "org.springframework.aop.framework.ReflectiveMethodInvocation",
"method": "proceed",
"file": "ReflectiveMethodInvocation.java",
"line": 184
},
{
"class": "org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation",
"method": "proceed",
"file": "CglibAopProxy.java",
"line": 768
},
{
"class": "org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor",
"method": "intercept",
"file": "CglibAopProxy.java",
"line": 720
},
{
"class": "com.amway.commerce.cartbizservice.app.controllers.CartController$$SpringCGLIB$$0",
"method": "updateCartBySubCartId",
"file": "<generated>",
"line": -1
},
{
"class": "jdk.internal.reflect.GeneratedMethodAccessor1259",
"method": "invoke",
"file": null,
"line": -1
},
{
"class": "jdk.internal.reflect.DelegatingMethodAccessorImpl",
"method": "invoke",
"file": "DelegatingMethodAccessorImpl.java",
"line": 43
},
{
"class": "java.lang.reflect.Method",
"method": "invoke",
"file": "Method.java",
"line": 569
},
{
"class": "org.springframework.web.method.support.InvocableHandlerMethod",
"method": "doInvoke",
"file": "InvocableHandlerMethod.java",
"line": 255
},
{
"class": "org.springframework.web.method.support.InvocableHandlerMethod",
"method": "invokeForRequest",
"file": "InvocableHandlerMethod.java",
"line": 188
},
{
"class": "org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod",
"method": "invokeAndHandle",
"file": "ServletInvocableHandlerMethod.java",
"line": 118
},
{
"class": "org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter",
"method": "invokeHandlerMethod",
"file": "RequestMappingHandlerAdapter.java",
"line": 926
},
{
"class": "org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter",
"method": "handleInternal",
"file": "RequestMappingHandlerAdapter.java",
"line": 831
},
{
"class": "org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter",
"method": "handle",
"file": "AbstractHandlerMethodAdapter.java",
"line": 87
},
{
"class": "org.springframework.web.servlet.DispatcherServlet",
"method": "doDispatch",
"file": "DispatcherServlet.java",
"line": 1089
},
{
"class": "org.springframework.web.servlet.DispatcherServlet",
"method": "doService",
"file": "DispatcherServlet.java",
"line": 979
},
{
"class": "org.springframework.web.servlet.FrameworkServlet",
"method": "processRequest",
"file": "FrameworkServlet.java",
"line": 1014
},
{
"class": "org.springframework.web.servlet.FrameworkServlet",
"method": "service",
"file": "FrameworkServlet.java",
"line": 888
},
{
"class": "jakarta.servlet.http.HttpServlet",
"method": "service",
"file": "HttpServlet.java",
"line": 658
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "internalDoFilter",
"file": "ApplicationFilterChain.java",
"line": 195
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "doFilter",
"file": "ApplicationFilterChain.java",
"line": 140
},
{
"class": "org.apache.tomcat.websocket.server.WsFilter",
"method": "doFilter",
"file": "WsFilter.java",
"line": 51
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "internalDoFilter",
"file": "ApplicationFilterChain.java",
"line": 164
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "doFilter",
"file": "ApplicationFilterChain.java",
"line": 140
},
{
"class": "org.springframework.web.filter.OncePerRequestFilter",
"method": "doFilter",
"file": "OncePerRequestFilter.java",
"line": 101
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "internalDoFilter",
"file": "ApplicationFilterChain.java",
"line": 164
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "doFilter",
"file": "ApplicationFilterChain.java",
"line": 140
},
{
"class": "com.amway.commerce.servicechassis.filter.TupleHeadersValidationFilter",
"method": "doFilterInternal",
"file": "TupleHeadersValidationFilter.java",
"line": 86
},
{
"class": "org.springframework.web.filter.OncePerRequestFilter",
"method": "doFilter",
"file": "OncePerRequestFilter.java",
"line": 116
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "internalDoFilter",
"file": "ApplicationFilterChain.java",
"line": 164
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "doFilter",
"file": "ApplicationFilterChain.java",
"line": 140
},
{
"class": "com.amway.commerce.servicechassis.security.filter.UserInfoLogFilter",
"method": "doFilter",
"file": "UserInfoLogFilter.java",
"line": 26
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "internalDoFilter",
"file": "ApplicationFilterChain.java",
"line": 164
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "doFilter",
"file": "ApplicationFilterChain.java",
"line": 140
},
{
"class": "com.amway.commerce.cartbizservice.app.config.CorsFilter",
"method": "doFilter",
"file": "CorsFilter.java",
"line": 56
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "internalDoFilter",
"file": "ApplicationFilterChain.java",
"line": 164
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "doFilter",
"file": "ApplicationFilterChain.java",
"line": 140
},
{
"class": "com.amway.commerce.servicechassis.logging.LogContextFilter",
"method": "doFilter",
"file": "LogContextFilter.java",
"line": 62
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "internalDoFilter",
"file": "ApplicationFilterChain.java",
"line": 164
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "doFilter",
"file": "ApplicationFilterChain.java",
"line": 140
},
{
"class": "org.springframework.web.filter.CompositeFilter$VirtualFilterChain",
"method": "doFilter",
"file": "CompositeFilter.java",
"line": 108
},
{
"class": "org.springframework.security.web.FilterChainProxy",
"method": "lambda$doFilterInternal$3",
"file": "FilterChainProxy.java",
"line": 231
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator",
"method": "lambda$wrapSecured$0",
"file": "ObservationFilterChainDecorator.java",
"line": 82
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 128
},
{
"class": "org.springframework.security.web.access.intercept.AuthorizationFilter",
"method": "doFilter",
"file": "AuthorizationFilter.java",
"line": 100
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "wrapFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 240
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 227
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 137
},
{
"class": "org.springframework.security.web.access.ExceptionTranslationFilter",
"method": "doFilter",
"file": "ExceptionTranslationFilter.java",
"line": 126
},
{
"class": "org.springframework.security.web.access.ExceptionTranslationFilter",
"method": "doFilter",
"file": "ExceptionTranslationFilter.java",
"line": 120
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "wrapFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 240
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 227
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 137
},
{
"class": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
"method": "doFilter",
"file": "SecurityContextHolderAwareRequestFilter.java",
"line": 179
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "wrapFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 240
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 227
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 137
},
{
"class": "org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter",
"method": "doFilterInternal",
"file": "BearerTokenAuthenticationFilter.java",
"line": 145
},
{
"class": "org.springframework.web.filter.OncePerRequestFilter",
"method": "doFilter",
"file": "OncePerRequestFilter.java",
"line": 116
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "wrapFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 240
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 227
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 137
},
{
"class": "org.springframework.security.web.header.HeaderWriterFilter",
"method": "doHeadersAfter",
"file": "HeaderWriterFilter.java",
"line": 90
},
{
"class": "org.springframework.security.web.header.HeaderWriterFilter",
"method": "doFilterInternal",
"file": "HeaderWriterFilter.java",
"line": 75
},
{
"class": "org.springframework.web.filter.OncePerRequestFilter",
"method": "doFilter",
"file": "OncePerRequestFilter.java",
"line": 116
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "wrapFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 240
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 227
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 137
},
{
"class": "org.springframework.security.web.context.SecurityContextHolderFilter",
"method": "doFilter",
"file": "SecurityContextHolderFilter.java",
"line": 82
},
{
"class": "org.springframework.security.web.context.SecurityContextHolderFilter",
"method": "doFilter",
"file": "SecurityContextHolderFilter.java",
"line": 69
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "wrapFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 240
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 227
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 137
},
{
"class": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter",
"method": "doFilterInternal",
"file": "WebAsyncManagerIntegrationFilter.java",
"line": 62
},
{
"class": "org.springframework.web.filter.OncePerRequestFilter",
"method": "doFilter",
"file": "OncePerRequestFilter.java",
"line": 116
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "wrapFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 240
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 224
},
{
"class": "org.springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain",
"method": "doFilter",
"file": "ObservationFilterChainDecorator.java",
"line": 137
},
{
"class": "org.springframework.security.web.FilterChainProxy",
"method": "doFilterInternal",
"file": "FilterChainProxy.java",
"line": 233
},
{
"class": "org.springframework.security.web.FilterChainProxy",
"method": "doFilter",
"file": "FilterChainProxy.java",
"line": 191
},
{
"class": "org.springframework.web.filter.CompositeFilter$VirtualFilterChain",
"method": "doFilter",
"file": "CompositeFilter.java",
"line": 113
},
{
"class": "org.springframework.web.servlet.handler.HandlerMappingIntrospector",
"method": "lambda$createCacheFilter$3",
"file": "HandlerMappingIntrospector.java",
"line": 195
},
{
"class": "org.springframework.web.filter.CompositeFilter$VirtualFilterChain",
"method": "doFilter",
"file": "CompositeFilter.java",
"line": 113
},
{
"class": "org.springframework.web.filter.CompositeFilter",
"method": "doFilter",
"file": "CompositeFilter.java",
"line": 74
},
{
"class": "org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy",
"method": "doFilter",
"file": "WebMvcSecurityConfiguration.java",
"line": 230
},
{
"class": "org.springframework.web.filter.DelegatingFilterProxy",
"method": "invokeDelegate",
"file": "DelegatingFilterProxy.java",
"line": 352
},
{
"class": "org.springframework.web.filter.DelegatingFilterProxy",
"method": "doFilter",
"file": "DelegatingFilterProxy.java",
"line": 268
},
{
"class": "org.apache.catalina.core.ApplicationFilterChain",
"method": "internalDoFilter",
"file": "ApplicationFilterChain.java",
"line": 164
}
]
}