{"record":{"id":"7aaa233fa649ecbd","repo":"oracle/graal","slug":"package-s-cannot-be-imported-from-multiple-loader","errorCode":null,"errorMessage":"Package %s cannot be imported from multiple loaders","messagePattern":"Package (.+?) cannot be imported from multiple loaders","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler.hostvmaccess/src/jdk/graal/compiler/hostvmaccess/HostVMAccessClassLoader.java","lineNumber":248,"sourceCode":"                    for (ModuleDescriptor.Exports e : descriptor.exports()) {\n                        if (!e.isQualified()) {\n                            remotePackage(remotePackageMap, e.source(), loader);\n                        }\n                    }\n                }\n            }\n        }\n\n        return Collections.unmodifiableMap(remotePackageMap);\n    }\n\n    /**\n     * See {@code jdk.internal.loader.Loader#remotePackage}.\n     */\n    private static void remotePackage(Map<String, ClassLoader> map, String pn, ClassLoader loader) {\n        ClassLoader l = map.putIfAbsent(pn, loader);\n        if (l != null && l != loader) {\n            throw new IllegalStateException(\"Package \" + pn + \" cannot be imported from multiple loaders\");\n        }\n    }\n\n    /**\n     * See {@code jdk.internal.loader.Loader#findModuleLayer}.\n     */\n    private static Optional<ModuleLayer> findModuleLayer(ModuleLayer moduleLayer, Configuration cf) {\n        return SharedSecrets.getJavaLangAccess().layers(moduleLayer) //\n                        .filter(l -> l.configuration() == cf) //\n                        .findAny();\n    }\n\n    /**\n     * See {@code jdk.internal.loader.Loader#findResource(String mn, String name)}.\n     */\n    @Override\n    protected URL findResource(String mn, String name) throws IOException {\n        /* For unnamed module, search for resource in class-path */","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler.hostvmaccess/src/jdk/graal/compiler/hostvmaccess/HostVMAccessClassLoader.java#L230-L266","documentation":"Mirroring jdk.internal.loader.Loader.remotePackage: while wiring the module configuration, each remote (parent-layer) package is mapped to the loader that provides it. If the same package would be imported from two different class loaders, the mapping is ambiguous and this IllegalStateException is thrown — JPMS forbids reading the same package from multiple loaders in one configuration.","triggerScenarios":"The module configuration given to HostVMAccessClassLoader resolves modules that 'requires transitive' the same package through two distinct parent loaders/layers (e.g. boot layer plus an custom parent layer that both expose com.example.api). Thrown during loader construction from remotePackage().","commonSituations":"Layering multiple module layers where a library is visible through two parent loaders (common in app servers, test frameworks, or nested image-build setups); mixing a custom parent ClassLoader that also loads modules from the boot layer.","solutions":["Ensure each package is readable from exactly one parent loader: deduplicate shared libraries so they are loaded only in the boot layer or only in the custom layer","Adjust the parent layer configuration passed to VMAccess so overlapping 'requires' edges are not resolved twice","Isolate conflicting modules into separate configurations/VMAccess instances instead of one shared layer"],"exampleFix":"# before\n# both boot layer and custom layer provide com.example.api\n--add-modules com.example.api --module-path custom/\n\n# after\n# load com.example.api only via boot layer; custom layer requires it, does not re-export\n# (drop the duplicate from the custom module path)","handlingStrategy":"validation","validationCode":"Set<String> seen = new HashSet<>();\nfor (String pn : localPackages) {\n    for (ModuleLayer parent : parentLayers) {\n        ClassLoader cl = parent.findLoader(parent.findModule(pn).orElseThrow().name());\n        // ensure each remote package maps to exactly one loader\n    }\n}","typeGuard":null,"tryCatchPattern":"catch (IllegalStateException e) { if (e.getMessage().contains(\"multiple loaders\")) { list parent layers exposing the package; deduplicate libraries; } }","preventionTips":["Design module layers so each library is loaded by exactly one loader","Avoid nesting image-build/parent configurations that re-export the same packages","Document which layer owns shared API packages in multi-layer setups"],"tags":["graalvm","jpms","module-layer","classloader","split-package"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}