grpc/grpc-java · error · UnsupportedOperationException

Channel state API is not implemented

Error message

Channel state API is not implemented

What it means

ConnectivityStateManager.getState() returns the channel's connectivity state, but the manager starts with no state set and only learns states once a transport reports them. Calling getState() on a channel whose transport never installed a state manager throws UnsupportedOperationException, indicating the channel's state API is not wired up.

Source

Thrown at core/src/main/java/io/grpc/internal/ConnectivityStateManager.java:85

        return;
      }
      // Swap out callback list before calling them, because a callback may register new callbacks,
      // if run in direct executor, can cause ConcurrentModificationException.
      ArrayList<Listener> savedListeners = listeners;
      listeners = new ArrayList<>();
      for (Listener listener : savedListeners) {
        listener.runInExecutor();
      }
    }
  }

  /**
   * Gets the current connectivity state of the channel. This method is threadsafe.
   */
  ConnectivityState getState() {
    ConnectivityState stateCopy = state;
    if (stateCopy == null) {
      throw new UnsupportedOperationException("Channel state API is not implemented");
    }
    return stateCopy;
  }

  private static final class Listener {
    final Runnable callback;
    final Executor executor;

    Listener(Runnable callback, Executor executor) {
      this.callback = callback;
      this.executor = executor;
    }

    void runInExecutor() {
      executor.execute(callback);
    }
  }
}

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Use a real transport (e.g. NettyChannelBuilder) that reports connectivity states instead of a test/minimal transport.
  2. Guard calls to Channel.getState() with a check of whether the transport supports the state API, or catch UnsupportedOperationException.
  3. If implementing a transport, ensure the LoadBalancer/transport calls the connectivity-state callbacks so the manager is initialized.

Example fix

// before
ConnectivityState state = channel.getState(false);
// after
ConnectivityState state;
try {
  state = channel.getState(false);
} catch (UnsupportedOperationException e) {
  state = ConnectivityState.IDLE; // transport does not expose state
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  state = channel.getState(false);
} catch (UnsupportedOperationException e) {
  state = null; // transport doesn't support state API
}

Prevention

When it happens

Trigger: Calling Channel.getState(false/true) on a channel implementation (typically a test transport or Channel/shim without state reporting) that never calls gotoState(), so the internal `state` field is still null.

Common situations: Using in-process or custom test transports that don't implement the state API; calling getState() before any connection attempt on a transport lacking state reporting; building a custom transport that forgot to propagate connectivity states.

Related errors


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