grpc/grpc-java · error · RuntimeException

Cannot create Epoll EventLoopGroup

Error message

Cannot create Epoll EventLoopGroup

What it means

gRPC's Netty transport tries to instantiate Netty's epoll EventLoopGroup reflectively when epoll is detected as available. If the reflective construction (EpollEventLoopGroup(parallelism, threadFactory)) throws any exception, it is wrapped in this RuntimeException. It means epoll support was present on the classpath but the actual group creation failed at runtime.

Source

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

          Class
              .forName("io.netty.channel.epoll.EpollServerSocketChannel")
              .asSubclass(ServerChannel.class);
      return serverSocketChannel;
    } catch (ClassNotFoundException e) {
      throw new RuntimeException("Cannot load EpollServerSocketChannel", e);
    }
  }

  private static EventLoopGroup createEpollEventLoopGroup(
      int parallelism,
      ThreadFactory threadFactory) {
    checkState(EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR != null, "Epoll is not available");

    try {
      return EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR
          .newInstance(parallelism, threadFactory);
    } catch (Exception e) {
      throw new RuntimeException("Cannot create Epoll EventLoopGroup", e);
    }
  }

  private static ChannelFactory<ServerChannel> nioServerChannelFactory() {
    return new ChannelFactory<ServerChannel>() {
      @Override
      public ServerChannel newChannel() {
        return new NioServerSocketChannel();
      }
    };
  }

  /**
   * Returns TCP_USER_TIMEOUT channel option for Epoll channel if Epoll is available, otherwise
   * null.
   */
  @Nullable
  static ChannelOption<Integer> maybeGetTcpUserTimeoutOption() {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Add the matching netty-transport-native-epoll classifier for your platform (e.g. linux-x86_64) so native libs are on the classpath
  2. Verify Epoll.isAvailable() (log Epoll.unavailabilityCause()) before relying on epoll, and fall back to NIO when unavailable
  3. Force NIO by using NettyChannelBuilder.channelType(NioSocketChannel.class)/nioServerChannelType or running on non-Linux where NIO is default
  4. If on Alpine/musl, include the 'musl' classified native artifact or use a glibc-based image
  5. Check that parallelism passed to the EventLoopGroup is a sane positive integer

Example fix

// before
ManagedChannel channel = NettyChannelBuilder.forAddress(host, port).build(); // picks epoll, throws
// after
NettyChannelBuilder builder = NettyChannelBuilder.forAddress(host, port);
if (Epoll.isAvailable()) {
  builder.channelType(EpollSocketChannel.class).eventLoopGroup(new EpollEventLoopGroup());
} else {
  builder.channelType(NioSocketChannel.class); // fallback
}
ManagedChannel channel = builder.build();
Defensive patterns

Strategy: fallback

Validate before calling

if (!Epoll.isAvailable()) {
  throw new IllegalStateException("epoll unavailable: " + Epoll.unavailabilityCause());
}

Type guard

boolean epollUsable() { try { Class.forName("io.netty.channel.epoll.EpollEventLoopGroup"); return Epoll.isAvailable(); } catch (ClassNotFoundException e) { return false; } }

Try / catch

try {
  channel = NettyChannelBuilder.forAddress(host, port).build();
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().contains("Cannot create Epoll EventLoopGroup")) {
    channel = NettyChannelBuilder.forAddress(host, port).channelType(NioSocketChannel.class).build();
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling ManagedChannelBuilder/ServerBuilder forNetty with channelType/DefaultEventLoopGroup creation on Linux when netty-transport-native-epoll's native library fails to load or the constructor rejects the arguments (e.g. invalid parallelism, missing native lib for the current arch like osx-aarch_64 or musl/alpine).

Common situations: Running in a container or Alpine/musl image whose libc doesn't match the bundled epoll native artifact; netty-transport-native-epoll classifier mismatch with the OS/arch; EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR was non-null (class found) but native libs are absent, so Epoll.isAvailable() checks passed inconsistently or constructor fails on first use.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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