grpc/grpc-java · error · NullPointerException
Factory returned null interceptor
Error message
Factory returned null interceptor: ${factory} What it means
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.
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.
Example fix
// before
public ClientInterceptor newInterceptor(String target) {
return enabled ? new MyInterceptor() : null;
}
// after
public ClientInterceptor newInterceptor(String target) {
return enabled ? new MyInterceptor() : ClientInterceptors.noop(new CallOptions() {}); // or unconditional interceptor
} Defensive patterns
Strategy: try-catch
Validate before calling
ClientInterceptorFactory f = ...;
if (f.newInterceptor(target) == null) {
throw new IllegalStateException("factory " + f + " returns null for target " + target);
} Type guard
ClientInterceptor safeNew(InterceptorFactory f, String target) {
ClientInterceptor ci = f.newInterceptor(target);
return ci != null ? ci : (call, next) -> next.startCall(call);
} Try / catch
try {
builder.intercept(factoryWrapper).build();
} catch (NullPointerException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Factory returned null interceptor")) {
log.error("Fix interceptor factory: {}", e.getMessage());
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Custom interceptor factories conditionally skipping targets; third-party instrumentation factories that fail to construct (returning null on missing config) rather than throwing.
Related errors
- Failed to translate authorization policy
- startCall() returned a null listener for method
- A key manager is required
- A terminal HttpFilter must be the last filter
- Address is not an IP
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/2a3121676e95f352.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java:806
new ExponentialBackoffPolicy.Provider(),
SharedResourcePool.forResource(GrpcUtil.SHARED_CHANNEL_EXECUTOR),
GrpcUtil.STOPWATCH_SUPPLIER,
getEffectiveInterceptors(resolvedResolver.targetUri.toString()),
TimeProvider.SYSTEM_TIME_PROVIDER));
}
// Temporarily disable retry when stats or tracing is enabled to avoid breakage, until we know
// what should be the desired behavior for retry + stats/tracing.
// TODO(zdapeng): FIX IT
@VisibleForTesting
List<ClientInterceptor> getEffectiveInterceptors(String computedTarget) {
List<ClientInterceptor> effectiveInterceptors = new ArrayList<>(this.interceptors.size());
for (ClientInterceptor interceptor : this.interceptors) {
if (interceptor instanceof InterceptorFactoryWrapper) {
InterceptorFactory factory = ((InterceptorFactoryWrapper) interceptor).factory;
interceptor = factory.newInterceptor(computedTarget);
if (interceptor == null) {
throw new NullPointerException("Factory returned null interceptor: " + factory);
}
}
effectiveInterceptors.add(interceptor);
}
boolean disableImplicitCensus = InternalConfiguratorRegistry.wasSetConfiguratorsCalled();
if (disableImplicitCensus) {
return effectiveInterceptors;
}
if (statsEnabled) {
ClientInterceptor statsInterceptor = null;
if (GET_CLIENT_INTERCEPTOR_METHOD != null) {
try {
statsInterceptor =
(ClientInterceptor) GET_CLIENT_INTERCEPTOR_METHOD
.invoke(
null,View on GitHub (pinned to 64daddc1f3)