apache/flink · error · IllegalAccessError
conflicting non-public interface class loaders
Error message
conflicting non-public interface class loaders
What it means
Inside InstantiationUtil's deserialization ObjectInputStream subclass, resolveProxyClass rebuilds java.lang.reflect.Proxy classes for serialized dynamic proxies. It mirrors the JDK rule: all non-public interfaces of a proxy must be loaded by the SAME classloader; if a second non-public interface comes from a different loader, it throws IllegalAccessError("conflicting non-public interface class loaders").
Source
Thrown at flink-core/src/main/java/org/apache/flink/util/InstantiationUtil.java:107
return super.resolveClass(desc);
}
@Override
protected Class<?> resolveProxyClass(String[] interfaces)
throws IOException, ClassNotFoundException {
if (classLoader != null) {
ClassLoader nonPublicLoader = null;
boolean hasNonPublicInterface = false;
// define proxy in class loader of non-public interface(s), if any
Class<?>[] classObjs = new Class<?>[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
Class<?> cl = Class.forName(interfaces[i], false, classLoader);
if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
if (hasNonPublicInterface) {
if (nonPublicLoader != cl.getClassLoader()) {
throw new IllegalAccessError(
"conflicting non-public interface class loaders");
}
} else {
nonPublicLoader = cl.getClassLoader();
hasNonPublicInterface = true;
}
}
classObjs[i] = cl;
}
try {
return Proxy.getProxyClass(
hasNonPublicInterface ? nonPublicLoader : classLoader, classObjs);
} catch (IllegalArgumentException e) {
throw new ClassNotFoundException(null, e);
}
}
return super.resolveProxyClass(interfaces);View on GitHub (pinned to 2f3c205e92)
Solutions
- Ensure each interface class exists in exactly ONE classloader: remove the jar from either the user job or Flink's lib/ so no duplicates exist
- Make the proxy interfaces public where you own them, so the non-public consistency rule no longer applies
- Avoid serializing JDK dynamic proxies in state/config payloads; serialize a plain DTO and rebuild the proxy after deserialization
Defensive patterns
Strategy: fallback
Try / catch
try {
Object o = InstantiationUtil.deserializeObject(bytes, cl);
} catch (IllegalAccessError e) {
// proxy interfaces split across loaders: fall back to parent-first loading of the shared lib
} Prevention
- Ship each library in exactly one classloader scope (lib/ XOR user jar)
- Avoid serializing dynamic proxies; transfer plain DTOs and rebuild proxies locally
- Prefer public interfaces for anything that crosses serialization boundaries
When it happens
Trigger: deserializeObject(bytes, cl) where the byte stream contains a Proxy object implementing multiple non-public interfaces (e.g. package-private interfaces from a library) that resolve to different classloaders under the given loader — typically when the same classes exist both in the parent loader and the user-code loader.
Common situations: Session clusters where a library ships both in Flink's lib/ and inside the user jar; deserializing cached/state objects after dependency relocation; classloader resolve-order changes causing interfaces to load from duplicate copies.
Related errors
- Cannot deserialize and unwrap accumulators properly.
- Failed to deserialize coordination response
- Cannot deserialize and unwrap accumulators properly.
- Unable to instantiate Hadoop InputSplit
- Unable to instantiate the hadoop input format
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/6372072fed2c12a3.
Report an issue: GitHub.