{"record":{"id":"2a3121676e95f352","repo":"grpc/grpc-java","slug":"factory-returned-null-interceptor-factory","errorCode":null,"errorMessage":"Factory returned null interceptor: ${factory}","messagePattern":"Factory returned null interceptor: (.+?)","errorType":"validation","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java","lineNumber":806,"sourceCode":"        new ExponentialBackoffPolicy.Provider(),\n        SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR),\n        GrpcUtil.STOPWATCH_SUPPLIER,\n        getEffectiveInterceptors(resolvedResolver.targetUri.toString()),\n        TimeProvider.SYSTEM_TIME_PROVIDER));\n  }\n\n  // Temporarily disable retry when stats or tracing is enabled to avoid breakage, until we know\n  // what should be the desired behavior for retry + stats/tracing.\n  // TODO(zdapeng): FIX IT\n  @VisibleForTesting\n  List<ClientInterceptor> getEffectiveInterceptors(String computedTarget) {\n    List<ClientInterceptor> effectiveInterceptors = new ArrayList<>(this.interceptors.size());\n    for (ClientInterceptor interceptor : this.interceptors) {\n      if (interceptor instanceof InterceptorFactoryWrapper) {\n        InterceptorFactory factory = ((InterceptorFactoryWrapper) interceptor).factory;\n        interceptor = factory.newInterceptor(computedTarget);\n        if (interceptor == null) {\n          throw new NullPointerException(\"Factory returned null interceptor: \" + factory);\n        }\n      }\n      effectiveInterceptors.add(interceptor);\n    }\n\n    boolean disableImplicitCensus = InternalConfiguratorRegistry.wasSetConfiguratorsCalled();\n    if (disableImplicitCensus) {\n      return effectiveInterceptors;\n    }\n    if (statsEnabled) {\n      ClientInterceptor statsInterceptor = null;\n\n      if (GET_CLIENT_INTERCEPTOR_METHOD != null) {\n        try {\n          statsInterceptor =\n              (ClientInterceptor) GET_CLIENT_INTERCEPTOR_METHOD\n              .invoke(\n                null,","sourceCodeStart":788,"sourceCodeEnd":824,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java#L788-L824","documentation":"When a ClientInterceptor registered via ManagedChannelImplBuilder wraps an InterceptorFactory, the factory is invoked with the resolved target to produce the actual interceptor. If the factory returns null, the builder throws a NullPointerException with this message identifying the factory, because a null interceptor would silently drop interception.","triggerScenarios":"Registering an interceptor whose InterceptorFactory.newInterceptor(computedTarget) returns null — e.g. a factory that disables itself for certain targets by returning null instead of a no-op interceptor.","commonSituations":"Custom interceptor factories conditionally skipping targets; third-party instrumentation factories that fail to construct (returning null on missing config) rather than throwing.","solutions":["Fix the factory to return a non-null interceptor (a no-op ClientInterceptor) for unsupported targets.","If the factory cannot operate, have it throw a descriptive exception instead of returning null.","Inspect the factory named in the message and add logging inside newInterceptor() to find the null-return path."],"exampleFix":"// before\npublic ClientInterceptor newInterceptor(String target) {\n  return enabled ? new MyInterceptor() : null;\n}\n// after\npublic ClientInterceptor newInterceptor(String target) {\n  return enabled ? new MyInterceptor() : ClientInterceptors.noop(new CallOptions() {}); // or unconditional interceptor\n}","handlingStrategy":"try-catch","validationCode":"ClientInterceptorFactory f = ...;\nif (f.newInterceptor(target) == null) {\n  throw new IllegalStateException(\"factory \" + f + \" returns null for target \" + target);\n}","typeGuard":"ClientInterceptor safeNew(InterceptorFactory f, String target) {\n  ClientInterceptor ci = f.newInterceptor(target);\n  return ci != null ? ci : (call, next) -> next.startCall(call);\n}","tryCatchPattern":"try {\n  builder.intercept(factoryWrapper).build();\n} catch (NullPointerException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Factory returned null interceptor\")) {\n    log.error(\"Fix interceptor factory: {}\", e.getMessage());\n  } else throw e;\n}","preventionTips":["Factories must always return a non-null interceptor; use a no-op for disabled cases.","Unit-test each InterceptorFactory with representative targets.","Throw a descriptive exception inside the factory rather than returning null."],"tags":["grpc","interceptor","null","factory"],"backgroundTag":"null-argument","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}