grpc/grpc-java · error · UnsupportedOperationException

Subclass failed to hide static factory

Error message

Subclass failed to hide static factory

What it means

ForwardingChannelBuilder2 is an abstract delegating wrapper around ManagedChannelBuilder. Its static forAddress() factory is marked @DoNotCall and exists only to force subclasses to define their own static forAddress(); invoking the inherited/base one throws UnsupportedOperationException because the wrapper cannot know which concrete builder to construct.

Source

Thrown at api/src/main/java/io/grpc/ForwardingChannelBuilder2.java:51

 *
 * @param <T> The type of the subclass extending this abstract class.
 * @since 1.59.0
 */
public abstract class ForwardingChannelBuilder2<T extends ManagedChannelBuilder<T>>
    extends ManagedChannelBuilder<T> {

  /**
   * The default constructor.
   */
  protected ForwardingChannelBuilder2() {
  }

  /**
   * This method serves to force subclasses to "hide" this static factory.
   */
  @DoNotCall("Unsupported")
  public static ManagedChannelBuilder<?> forAddress(String name, int port) {
    throw new UnsupportedOperationException("Subclass failed to hide static factory");
  }

  /**
   * This method serves to force subclasses to "hide" this static factory.
   */
  @DoNotCall("Unsupported")
  public static ManagedChannelBuilder<?> forTarget(String target) {
    throw new UnsupportedOperationException("Subclass failed to hide static factory");
  }

  /**
   * Returns the delegated {@code ManagedChannelBuilder}.
   */
  protected abstract ManagedChannelBuilder<?> delegate();

  @Override
  public T directExecutor() {
    delegate().directExecutor();

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Call the concrete builder's static factory, e.g. MyForwardingBuilder.forAddress(name, port), never ForwardingChannelBuilder2.forAddress
  2. If you maintain a forwarding subclass, add your own static forAddress(String, int) that delegates to your delegate() implementation
  3. If resolving reflectively, look up the method on the actual subclass Class, not the base class

Example fix

// before
ManagedChannelBuilder<?> b = ForwardingChannelBuilder2.forAddress("localhost", 8080);
// after
ManagedChannelBuilder<?> b = MyGrpcChannelBuilder.forAddress("localhost", 8080); // subclass's own static factory
Defensive patterns

Strategy: validation

Validate before calling

// Never reference the base static factory; verify you are calling the subclass's own
Class<?> concrete = MyGrpcChannelBuilder.class;
if (concrete.getMethod("forAddress", String.class, int.class).getDeclaringClass()
    == io.grpc.ForwardingChannelBuilder2.class) {
  throw new IllegalStateException("Subclass must shadow forAddress");
}

Try / catch

try {
  builder = MyGrpcChannelBuilder.forAddress(name, port);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("Subclass failed to hide static factory")) {
    builder = ManagedChannelBuilder.forAddress(name, port); // fall back to standard builder
  } else throw e;
}

Prevention

When it happens

Trigger: Calling ForwardingChannelBuilder2.forAddress(host, port) directly instead of the subclass's static factory, or calling it through a subclass that failed to shadow (hide) the static method with its own forAddress implementation. Static methods resolve at compile time on the named class, so referencing the base method always hits this throw.

Common situations: Reflection or generic code that resolves the static factory on ForwardingChannelBuilder2.class rather than the concrete subclass; a custom forwarding builder that forgot to declare its own forAddress; IDE auto-import picking the wrong class.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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