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

  1. 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
  2. Make the proxy interfaces public where you own them, so the non-public consistency rule no longer applies
  3. 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

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


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/6372072fed2c12a3. Report an issue: GitHub.