grpc/grpc-java · error · RuntimeException
Cannot load EpollSocketChannel
Error message
Cannot load EpollSocketChannel
What it means
gRPC-netty tries to load io.netty.channel.epoll.EpollSocketChannel via reflection to support epoll transport on Linux. This RuntimeException wraps the ClassNotFoundException raised when the netty-transport-native-epoll artifact (or its epoll native binding) is not on the classpath. It means the code path requiring epoll was entered but the epoll classes are absent.
Solutions
- Add the dependency io.netty:netty-transport-native-epoll with the linux-x86_64 (or relevant) classifier matching your grpc-netty version
- Verify the Netty version on the classpath matches the one grpc-netty expects (mvn dependency:tree); align versions with the netty-bom
- If epoll is not needed, stop requesting the epoll channel type and let gRPC use the default NIO channel (NettyChannelBuilder defaults)
- Check that your build/packaging (shade plugin, container image) includes io/netty/channel/epoll/** classes and the native epoll .so library
Example fix
// before (pom.xml) <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> </dependency> // after <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-transport-native-epoll</artifactId> <classifier>linux-x86_64</classifier> </dependency>
Defensive patterns
Strategy: fallback
Validate before calling
boolean epollAvailable = false;
try {
Class.forName("io.netty.channel.epoll.EpollSocketChannel");
epollAvailable = true;
} catch (ClassNotFoundException e) {
// epoll transport not on classpath
} Type guard
static boolean hasEpollTransport() {
try {
Class.forName("io.netty.channel.epoll.EpollSocketChannel");
return true;
} catch (Throwable t) {
return false;
}
} Try / catch
try {
builder.channelType(io.grpc.netty.Utils.EPOLL_CHANNEL_TYPE);
} catch (RuntimeException e) {
if (e.getCause() instanceof ClassNotFoundException) {
builder.channelType(io.netty.channel.socket.nio.NioSocketChannel.class); // fall back to NIO
} else {
throw e;
}
} Prevention
- Always include netty-transport-native-epoll with the correct OS classifier when targeting Linux epoll
- Check Utils.isEpollAvailable() (or Class.forName probe) before requesting epoll channel types
- Let NettyChannelBuilder auto-detect the transport instead of hardcoding epoll
- Keep Netty versions aligned with grpc-netty via netty-bom
- Verify shaded/docker images retain epoll classes and native .so files
When it happens
Trigger: Calling Utils.epollChannelType() (indirectly through Utils.DEFAULT_CHANNEL_TYPE / EpollSocketChannel type resolution) when grpc-netty selects the epoll transport — e.g. channelBuilder.channelType(Utils.epollChannelType()) or default epoll detection — while io.netty:netty-transport-native-epoll is missing from the runtime classpath.
Common situations: Running on Linux with an epoll transport configured but the netty-transport-native-epoll dependency excluded or not transitively pulled in; fat-jar repackaging that drops epoll natives; mismatched Netty versions where io.netty.channel.epoll classes moved; deploying to a non-Linux OS while code unconditionally requests epoll channels.
Related errors
- Cannot create Epoll EventLoopGroup
- Cannot load EpollDomainSocketChannel
- Cannot load EpollEventLoopGroup
- Cannot load EpollServerSocketChannel
- EpollEventLoopGroup constructor not found
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/32d49fec5fdd9e75.
Report an issue: GitHub.
Appendix: source
Thrown at netty/src/main/java/io/grpc/netty/Utils.java:400
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 {
Class<? extends Channel> channelType = Class
.forName("io.netty.channel.epoll.EpollSocketChannel").asSubclass(Channel.class);
return channelType;
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot load EpollSocketChannel", e);
}
}
// Must call when epoll is available
private static Class<? extends Channel> epollDomainSocketChannelType() {
try {
Class<? extends Channel> channelType = Class
.forName("io.netty.channel.epoll.EpollDomainSocketChannel").asSubclass(Channel.class);
return channelType;
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot load EpollDomainSocketChannel", e);
}
}
// Must call when epoll is available
private static Constructor<? extends EventLoopGroup> epollEventLoopGroupConstructor() {
try {
return ClassView on GitHub (pinned to 64daddc1f3)