grpc/grpc-java · error · UnsupportedOperationException

ClientTransportFactoryBuilder is required, use a constructor

Error message

ClientTransportFactoryBuilder is required, use a constructor

What it means

ManagedChannelImplBuilder extends ManagedChannelBuilder but is internal; unlike public builders it requires a ClientTransportFactory (supplied via a constructor or transport builder) to know how to create connections. The inherited static forAddress() factory method is annotated @DoNotCall and always throws UnsupportedOperationException to steer users to the correct constructors.

Solutions

  1. Use io.grpc.ManagedChannelBuilder.forAddress(name, port) (the public API) instead.
  2. If you truly need the internal builder, use its constructor with a ClientTransportFactoryBuilder argument.
  3. Fix the import statement so the public builder class is referenced.

Example fix

// before
import io.grpc.internal.ManagedChannelImplBuilder;
ManagedChannelBuilder<?> b = ManagedChannelImplBuilder.forAddress("localhost", 50051);
// after
import io.grpc.ManagedChannelBuilder;
ManagedChannelBuilder<?> b = ManagedChannelBuilder.forAddress("localhost", 50051);
Defensive patterns

Strategy: type-guard

Validate before calling

Class<?> c = builder.getClass();
if (c.getName().equals("io.grpc.internal.ManagedChannelImplBuilder")) {
  throw new IllegalStateException("Use io.grpc.ManagedChannelBuilder");
}

Type guard

boolean isPublicBuilder(ManagedChannelBuilder<?> b) {
  return !b.getClass().getName().startsWith("io.grpc.internal.");
}

Try / catch

try {
  return builder.forAddress(host, port);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("ClientTransportFactoryBuilder")) {
    return io.grpc.ManagedChannelBuilder.forAddress(host, port);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling ManagedChannelImplBuilder.forAddress(name, port) directly, e.g. via reflection or by mistyping the import so ManagedChannelImplBuilder is used instead of ManagedChannelBuilder.

Common situations: Import confusion between io.grpc.ManagedChannelBuilder and io.grpc.internal.ManagedChannelImplBuilder; framework code instantiating the internal builder through its static API.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java:84

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.annotation.Nullable;

/**
 * Default managed channel builder, for usage in Transport implementations.
 */
public final class ManagedChannelImplBuilder
    extends ManagedChannelBuilder<ManagedChannelImplBuilder> {
  private static final String DIRECT_ADDRESS_SCHEME = "directaddress";

  private static final Logger log = Logger.getLogger(ManagedChannelImplBuilder.class.getName());

  @DoNotCall("ClientTransportFactoryBuilder is required, use a constructor")
  public static ManagedChannelBuilder<?> forAddress(String name, int port) {
    throw new UnsupportedOperationException(
        "ClientTransportFactoryBuilder is required, use a constructor");
  }

  @DoNotCall("ClientTransportFactoryBuilder is required, use a constructor")
  public static ManagedChannelBuilder<?> forTarget(String target) {
    throw new UnsupportedOperationException(
        "ClientTransportFactoryBuilder is required, use a constructor");
  }

  /**
   * An idle timeout larger than this would disable idle mode.
   */
  @VisibleForTesting
  static final long IDLE_MODE_MAX_TIMEOUT_DAYS = 30;

  /**
   * The default idle timeout.
   */

View on GitHub (pinned to 64daddc1f3)