{"record":{"id":"6372072fed2c12a3","repo":"apache/flink","slug":"conflicting-non-public-interface-class-loaders","errorCode":null,"errorMessage":"conflicting non-public interface class loaders","messagePattern":"conflicting non-public interface class loaders","errorType":"exception","errorClass":"IllegalAccessError","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/util/InstantiationUtil.java","lineNumber":107,"sourceCode":"\n            return super.resolveClass(desc);\n        }\n\n        @Override\n        protected Class<?> resolveProxyClass(String[] interfaces)\n                throws IOException, ClassNotFoundException {\n            if (classLoader != null) {\n                ClassLoader nonPublicLoader = null;\n                boolean hasNonPublicInterface = false;\n\n                // define proxy in class loader of non-public interface(s), if any\n                Class<?>[] classObjs = new Class<?>[interfaces.length];\n                for (int i = 0; i < interfaces.length; i++) {\n                    Class<?> cl = Class.forName(interfaces[i], false, classLoader);\n                    if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {\n                        if (hasNonPublicInterface) {\n                            if (nonPublicLoader != cl.getClassLoader()) {\n                                throw new IllegalAccessError(\n                                        \"conflicting non-public interface class loaders\");\n                            }\n                        } else {\n                            nonPublicLoader = cl.getClassLoader();\n                            hasNonPublicInterface = true;\n                        }\n                    }\n                    classObjs[i] = cl;\n                }\n                try {\n                    return Proxy.getProxyClass(\n                            hasNonPublicInterface ? nonPublicLoader : classLoader, classObjs);\n                } catch (IllegalArgumentException e) {\n                    throw new ClassNotFoundException(null, e);\n                }\n            }\n\n            return super.resolveProxyClass(interfaces);","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/util/InstantiationUtil.java#L89-L125","documentation":"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\").","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    Object o = InstantiationUtil.deserializeObject(bytes, cl);\n} catch (IllegalAccessError e) {\n    // proxy interfaces split across loaders: fall back to parent-first loading of the shared lib\n}","preventionTips":["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"],"tags":["serialization","classloader","proxy","duplicate-classes"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}