grpc/grpc-java · error · IllegalStateException

NameResolverRegistry is not set in Builder

Error message

NameResolverRegistry is not set in Builder

What it means

NameResolver.Args.Builder.getNameResolverRegistry() throws IllegalStateException when nameResolverRegistry was never set via setNameResolverRegistry(). The registry (experimental since 1.74.0) lets a NameResolver look up nested providers to create child resolvers. Accessing it on Args built without it is an invariant violation: gRPC always sets this field when constructing Args internally, so null indicates the Args came from incomplete custom code.

Source

Thrown at api/src/main/java/io/grpc/NameResolver.java:525

      return overrideAuthority;
    }

    /**
     * Returns the {@link MetricRecorder} that the channel uses to record metrics.
     */
    public MetricRecorder getMetricRecorder() {
      return metricRecorder;
    }

    /**
     * Returns the {@link NameResolverRegistry} that the Channel uses to look for {@link
     * NameResolver}s.
     *
     * @since 1.74.0
     */
    public NameResolverRegistry getNameResolverRegistry() {
      if (nameResolverRegistry == null) {
        throw new IllegalStateException("NameResolverRegistry is not set in Builder");
      }
      return nameResolverRegistry;
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this)
          .add("defaultPort", defaultPort)
          .add("proxyDetector", proxyDetector)
          .add("syncContext", syncContext)
          .add("serviceConfigParser", serviceConfigParser)
          .add("customArgs", customArgs)
          .add("scheduledExecutorService", scheduledExecutorService)
          .add("channelLogger", channelLogger)
          .add("executor", executor)
          .add("overrideAuthority", overrideAuthority)
          .add("metricRecorder", metricRecorder)
          .add("nameResolverRegistry", nameResolverRegistry)

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Add setNameResolverRegistry(NameResolverRegistry.getDefaultRegistry()) or the channel-provided registry on the Args.Builder before build()
  2. If you don't need the registry, avoid calling getNameResolverRegistry() on hand-built Args and pass dependencies explicitly to your resolver constructor instead
  3. Check for gRPC version skew: ensure the component constructing NameResolver.Args is on a version >= 1.74.0 that populates the registry field

Example fix

// before
NameResolver.Args args = new NameResolver.Args.Builder()
    .setUri(uri)
    .build();
NameResolverRegistry registry = args.getNameResolverRegistry(); // throws

// after
NameResolver.Args args = new NameResolver.Args.Builder()
    .setUri(uri)
    .setNameResolverRegistry(NameResolverRegistry.getDefaultRegistry())
    .build();
NameResolverRegistry registry = args.getNameResolverRegistry();
Defensive patterns

Strategy: validation

Validate before calling

// before consuming Args
NameResolverRegistry registry;
try {
  registry = args.getNameResolverRegistry();
} catch (IllegalStateException e) {
  registry = NameResolverRegistry.getDefaultRegistry();
}

Type guard

boolean hasRegistry(NameResolver.Args args) {
  try { return args.getNameResolverRegistry() != null; }
  catch (IllegalStateException e) { return false; }
}

Try / catch

try {
  registry = args.getNameResolverRegistry();
} catch (IllegalStateException e) {
  registry = NameResolverRegistry.getDefaultRegistry();
}

Prevention

When it happens

Trigger: Calling getNameResolverRegistry() on NameResolver.Args whose Builder lacked a setNameResolverRegistry(...) call — e.g. inside a custom NameResolverProvider.newNameResolver that reads the registry, while the Args were assembled by test code or an older builder invocation that predates the 1.74.0 field.

Common situations: Custom NameResolver implementations that delegate to child resolvers via the registry; unit tests building Args manually; mixing gRPC versions where an integration layer (e.g. grpc-xds or a third-party resolver) builds Args without the registry field set.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/583709e0f435355e. Report an issue: GitHub.