grpc/grpc-java · error · RuntimeException
Cannot load EpollServerSocketChannel
Error message
Cannot load EpollServerSocketChannel
What it means
gRPC-netty loads io.netty.channel.epoll.EpollServerSocketChannel reflectively when configuring an epoll-based server. This RuntimeException wraps the ClassNotFoundException raised when the epoll transport classes are absent from the classpath. It is thrown only after the code has already assumed epoll is available, so it signals a missing/mispackaged epoll dependency.
Source
Thrown at netty/src/main/java/io/grpc/netty/Utils.java:437
.forName("io.netty.channel.epoll.EpollEventLoopGroup").asSubclass(EventLoopGroup.class)
.getConstructor(Integer.TYPE, ThreadFactory.class);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot load EpollEventLoopGroup", e);
} catch (NoSuchMethodException e) {
throw new RuntimeException("EpollEventLoopGroup constructor not found", e);
}
}
// Must call when epoll is available
private static Class<? extends ServerChannel> epollServerChannelType() {
try {
Class<? extends ServerChannel> serverSocketChannel =
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>() {View on GitHub (pinned to 64daddc1f3)
Solutions
- Add io.netty:netty-transport-native-epoll with the matching linux classifier and Netty version to the server's runtime classpath
- Verify the packaged artifact (jar/image) contains io/netty/channel/epoll/EpollServerSocketChannel and the native epoll .so
- Use a consistent Netty version (netty-bom) so grpc-netty's reflective lookups resolve
- Only enable the epoll transport on Linux; otherwise rely on the default NIO transport
Example fix
// before (build.gradle) implementation 'io.grpc:grpc-netty-shaded:1.x' // or grpc-netty without epoll natives // after implementation 'io.grpc:grpc-netty:1.x' runtimeOnly 'io.netty:netty-transport-native-epoll:4.1.100.Final:linux-x86_64' runtimeOnly 'io.netty:netty-transport-native-unix-common:4.1.100.Final:linux-x86_64'
Defensive patterns
Strategy: fallback
Validate before calling
static boolean epollServerTransportReady() {
try {
Class.forName("io.netty.channel.epoll.EpollServerSocketChannel");
return true;
} catch (ClassNotFoundException e) {
return false;
}
} Type guard
static Class<? extends io.netty.channel.ServerChannel> serverChannelTypeOrNio() {
try {
return io.grpc.netty.Utils.EPOLL_SERVER_CHANNEL_TYPE;
} catch (Throwable t) {
return io.netty.channel.socket.nio.NioServerSocketChannel.class;
}
} Try / catch
try {
return NettyServerBuilder.forPort(port)
.channelType(io.grpc.netty.Utils.EPOLL_SERVER_CHANNEL_TYPE)
.build();
} catch (RuntimeException e) {
if (e.getCause() instanceof ClassNotFoundException) {
return NettyServerBuilder.forPort(port) // default NIO transport
.build();
}
throw e;
} Prevention
- Add netty-transport-native-epoll runtime dependency for Linux server deployments
- Confirm the deployment image includes both epoll classes and the native .so
- Let gRPC auto-detect transport rather than forcing epoll
- Gate epoll usage on Linux OS check at startup
- Keep Netty versions aligned via netty-bom in dependencyManagement
When it happens
Trigger: Starting a gRPC server on the epoll transport, which calls Utils.epollServerChannelType() to resolve the server channel class, while io.netty:netty-transport-native-epoll is missing from the runtime classpath.
Common situations: Deploying gRPC servers to Linux with epoll transport enabled (explicitly or via default detection) but the slim Docker image or shaded jar omitted netty-transport-native-epoll; Netty version mismatch removing io.netty.channel.epoll classes; non-Linux deployment accidentally taking the epoll path.
Related errors
- Cannot load EpollSocketChannel
- Cannot load EpollDomainSocketChannel
- Cannot load EpollEventLoopGroup
- ${result.error}
- Exception while checking Epoll availability
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/8e9bcf10397687ef.
Report an issue: GitHub.