grpc/grpc-java · error · IllegalStateException

ChannelLogger is not set in Builder

Error message

ChannelLogger is not set in Builder

What it means

NameResolver.Args.Builder.getChannelLogger() throws IllegalStateException when channelLogger was never set via setChannelLogger(). The ChannelLogger is an experimental API component (since 1.26.0) that NameResolver implementations use to emit channel-level trace logs. gRPC requires it to be provided before the Args object is consumed, so reading it in an unset state is treated as a programming/invariant error rather than a recoverable failure.

Source

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

     *
     * <p>Custom args can also be used simply to avoid adding inappropriate deps to the low level
     * io.grpc package.
     */
    @SuppressWarnings("unchecked") // Cast is safe because all put()s go through the setArg() API.
    @Nullable
    public <T> T getArg(Key<T> key) {
      return customArgs != null ? (T) customArgs.get(key) : null;
    }

    /**
     * Returns the {@link ChannelLogger} for the Channel served by this NameResolver.
     *
     * @since 1.26.0
     */
    @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6438")
    public ChannelLogger getChannelLogger() {
      if (channelLogger == null) {
        throw new IllegalStateException("ChannelLogger is not set in Builder");
      }
      return channelLogger;
    }

    /**
     * Returns the configurator for child channels.
     *
     * @since 1.83.0
     */
    @ExperimentalApi("https://github.com/grpc/grpc-java/issues/12574")
    public ChannelConfigurator getChildChannelConfigurator() {
      return channelConfigurator;
    }

    /**
     * Returns the Executor on which this resolver should execute long-running or I/O bound work.
     * Null if no Executor was set.
     *

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Call setChannelLogger(...) on the Args.Builder before building, e.g. with args.getChannelLogger() passed in from the channel, or a Noop/Testing logger in tests
  2. Guard the call: use args.getChannelLogger() only inside a NameResolver whose Args were supplied by grpc's ManagedChannel (which always sets it); for hand-built Args in tests, substitute a simple ChannelLogger implementation
  3. If the Args come from your own provider code, audit the builder call chain and add the missing setChannelLogger call

Example fix

// before
NameResolver.Args args = new NameResolver.Args.Builder()
    .setUri(uri)
    .setAttributes(attributes)
    .build();
ChannelLogger logger = args.getChannelLogger(); // throws IllegalStateException

// after
NameResolver.Args args = new NameResolver.Args.Builder()
    .setUri(uri)
    .setAttributes(attributes)
    .setChannelLogger(channelLogger)
    .build();
ChannelLogger logger = args.getChannelLogger();
Defensive patterns

Strategy: validation

Validate before calling

// before consuming Args
if (args.getChannelLoggerOrNull() == null) { // or track your own builder flag
  throw new IllegalArgumentException("NameResolver.Args built without setChannelLogger");
}
ChannelLogger logger = args.getChannelLogger();

Type guard

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

Try / catch

try {
  logger = args.getChannelLogger();
} catch (IllegalStateException e) {
  logger = new NoopChannelLogger(); // fall back in tests/custom builders
}

Prevention

When it happens

Trigger: Calling getChannelLogger() on a NameResolver.Args instance built by a Builder on which setChannelLogger() was never called — typically a custom NameResolver implementation reading Args inside its factory (newNameResolver) or when the Args were constructed by non-gRPC code that omitted the field.

Common situations: Implementing a custom NameResolver/NameResolverProvider and calling args.getChannelLogger() while testing with a hand-built Args.Builder that only sets the fields you know about; upgrading gRPC where a previously optional Args field became required for your code path; unit tests that construct NameResolver.Args directly instead of receiving them from the channel.

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/1507e84cb5ff8794. Report an issue: GitHub.