grpc/grpc-java · error · RuntimeException
Cannot load EpollEventLoopGroup
Error message
Cannot load EpollEventLoopGroup
What it means
gRPC-netty reflectively loads io.netty.channel.epoll.EpollEventLoopGroup and looks up its (int, ThreadFactory) constructor. This RuntimeException wraps ClassNotFoundException, meaning the epoll transport classes are missing from the classpath at the moment the epoll event loop group is created.
Source
Thrown at netty/src/main/java/io/grpc/netty/Utils.java:422
// 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 Class
.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);
}
}
View on GitHub (pinned to 64daddc1f3)
Solutions
- Add io.netty:netty-transport-native-epoll with a linux classifier matching your platform and Netty version
- Verify with dependency:tree that only one consistent Netty version is present and it contains EpollEventLoopGroup
- If epoll transport was configured explicitly (transport(...)/epoll option), remove that setting to fall back to the default NIO event loop group
- Ensure the native epoll library (.so) is packaged — the classes alone are insufficient if the native binding is also stripped
Example fix
// before
NettyServerBuilder.forPort(8080)
.transport(NettyServerBuilder.EPOLL) // requires epoll on classpath
.build();
// after — add to build:
// implementation 'io.netty:netty-transport-native-epoll:4.1.x:linux-x86_64'
NettyServerBuilder.forPort(8080)
.transport(NettyServerBuilder.EPOLL)
.build(); Defensive patterns
Strategy: fallback
Validate before calling
static boolean epollEventLoopAvailable() {
try {
Class.forName("io.netty.channel.epoll.EpollEventLoopGroup")
.getConstructor(Integer.TYPE, ThreadFactory.class);
return true;
} catch (ClassNotFoundException | NoSuchMethodException e) {
return false;
}
} Type guard
static boolean canCreateEpollEventLoopGroup() {
try {
Class<?> c = Class.forName("io.netty.channel.epoll.EpollEventLoopGroup");
return c.getConstructor(Integer.TYPE, ThreadFactory.class) != null;
} catch (Throwable t) {
return false;
}
} Try / catch
try {
builder.eventLoopGroup(io.grpc.netty.Utils.createEpollEventLoopGroup(cores, factory));
} catch (RuntimeException e) {
if (e.getCause() instanceof ClassNotFoundException) {
builder.eventLoopGroup(new NioEventLoopGroup(cores, factory));
} else {
throw e;
}
} Prevention
- Include netty-transport-native-epoll (linux classifier) whenever epoll transport is configured
- Verify the (int, ThreadFactory) constructor exists in your Netty version before reflecting
- Pin Netty versions with netty-bom to avoid unexpected upgrades
- Avoid hardcoding epoll event loop groups; rely on gRPC defaults where possible
- Confirm native epoll .so is packaged alongside the classes
When it happens
Trigger: Creating the epoll event loop group via Utils.epollEventLoopGroupConstructor() when building an epoll-based channel/server (Utils.createEpollEventLoopGroup) while io.netty:netty-transport-native-epoll is not on the runtime classpath.
Common situations: Using EpollEventLoopGroupConfigured transport options (NettyServerBuilder/NettyChannelBuilder with epoll transport) on Linux where the native epoll dependency was not bundled; Netty version drift causing io.netty.channel.epoll.EpollEventLoopGroup to disappear from the jar set; shaded jars missing epoll classes.
Related errors
- Cannot load EpollSocketChannel
- Cannot load EpollDomainSocketChannel
- Cannot load EpollServerSocketChannel
- Exception while checking Epoll availability
- EpollEventLoopGroup constructor not found
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/5537badd1e506b32.
Report an issue: GitHub.