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.

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)

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.