Skip to content

[BUG] NullPointerError encountered while running flagd in NoOpProvider mode #1370

Closed
@ashish20790

Description

@ashish20790

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
    }
  ]
}

Metadata

Metadata

Assignees

Labels

Needs TriageThis issue needs to be investigated by a maintainerbugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions