grpc/grpc-java · error · RuntimeException

Exception while checking Epoll availability

Error message

Exception while checking Epoll availability

What it means

Utils.isEpollAvailable() reflectively invokes io.netty.channel.epoll.Epoll.isAvailable(). ClassNotFoundException (epoll jar absent) is treated as "not available", but any other reflective failure is rethrown as an unchecked RuntimeException "Exception while checking Epoll availability". This indicates the epoll probe itself broke, not merely that epoll is unavailable.

Source

Thrown at netty/src/main/java/io/grpc/netty/Utils.java:377

    if (t instanceof Http2Exception) {
      return Status.INTERNAL.withDescription("http2 exception").withCause(t);
    }
    return s;
  }

  @VisibleForTesting
  static boolean isEpollAvailable() {
    try {
      return (boolean) (Boolean)
          Class
              .forName("io.netty.channel.epoll.Epoll")
              .getDeclaredMethod("isAvailable")
              .invoke(null);
    } catch (ClassNotFoundException e) {
      // this is normal if netty-epoll runtime dependency doesn't exist.
      return false;
    } catch (Exception e) {
      throw new RuntimeException("Exception while checking Epoll availability", e);
    }
  }

  private static Throwable getEpollUnavailabilityCause() {
    try {
      return (Throwable)
          Class
              .forName("io.netty.channel.epoll.Epoll")
              .getDeclaredMethod("unavailabilityCause")
              .invoke(null);
    } catch (Exception e) {
      return e;
    }
  }

  // Must call when epoll is available
  private static Class<? extends Channel> epollChannelType() {
    try {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Read the cause: it reveals whether native library loading failed or reflection was blocked.
  2. Add the correct netty-transport-native-epoll artifact for your OS/arch (or the `netty-transport-native-epoll` with linux-x86_64 classifier) matching your netty version.
  3. Fix packaging so native .so files survive shading/fat-jar assembly, or disable epoll by using NIO (default) instead of forcing epoll.
  4. If running on non-Linux, use the default NIO transport rather than EpollChannelType.
  5. Call Epoll.isAvailable()/Epoll.autoDetection() semantics first and fall back to NIO when unavailable.

Example fix

// before
if (Utils.isEpollAvailable()) { ... } // throws when native lib is broken
// after
if (Epoll.isAvailable()) {
  channelType = EpollDomainSocket/EpollSocketChannel; // native present
} else {
  channelType = NioSocketChannel; // safe fallback
}
Defensive patterns

Strategy: fallback

Validate before calling

boolean epollUsable = io.netty.channel.epoll.Epoll.isAvailable(); // no exception: returns false when jar/native missing
Class<? extends io.netty.channel.Channel> channelType = epollUsable
    ? io.netty.channel.epoll.EpollSocketChannel
    : io.netty.channel.nio.NioSocketChannel;

Type guard

static boolean epollSafeToUse() {
  try {
    return Utils.isEpollAvailable();
  } catch (RuntimeException e) {
    return false; // treat broken epoll probe as unavailable
  }
}

Try / catch

try {
  useEpoll();
} catch (RuntimeException e) {
  if (e.getMessage().contains("Epoll availability")) {
    useNio(); // fall back to JDK NIO transport
  }
}

Prevention

When it happens

Trigger: Calling isEpollAvailable() (directly or via Utils/EpollChannelOption setup on Linux) when reflective invocation of Epoll.isAvailable() throws — e.g. the native epoll library failed to load (UnsatisfiedLinkError wrapped in ExceptionInInitializerError), SecurityManager blocking reflection, or a corrupted/partial netty-transport-native-epoll installation.

Common situations: Deploying grpc-netty without the matching netty-transport-native-epoll classifier jar (wrong OS/arch classifier); Alpine/musl images without the glibc epoll native build; fat jars excluding native .so files; running on non-Linux with code paths that assume epoll and mishandle the exception.

Understand the failure class

Background: "X is not installed. Please install it with pip install Y": missing optional dependency errors — ImportError/ValueError raised when a library's optional extra was never installed — this error's family across 22 libraries.

Related errors


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