oracle/graal · error · IllegalArgumentException
Must not call isAutomatic() on an unnamed module
Error message
Must not call isAutomatic() on an unnamed module
What it means
EspressoExternalResolvedJavaModule.isAutomatic() throws when called on a module whose name is null, i.e. an unnamed module. The JVMCI contract for ResolvedJavaModule states isAutomatic() is only valid for named modules, and this Espresso-backed implementation enforces that by checking isNamed() first. The descriptor lookup (java.lang.Module.getDescriptor) would itself fail or be meaningless for an unnamed module, so the call is rejected up front.
Solutions
- Call module.isNamed() before calling isAutomatic() and treat unnamed modules as non-automatic (return false in your wrapper).
- Verify the guest VM is launched with a module system if your code assumes named modules (check the Espresso launch configuration).
- Audit any framework code (annotation processors, service-loader scanning) that unconditionally queries isAutomatic() on classes from the unnamed module.
Example fix
// before boolean auto = module.isAutomatic(); // after boolean auto = module.isNamed() && module.isAutomatic();
Defensive patterns
Strategy: type-guard
Validate before calling
if (!module.isNamed()) {
// treat as non-automatic; skip descriptor queries
return false;
} Type guard
boolean canQueryDescriptor(ResolvedJavaModule m) { return m.isNamed(); } Try / catch
catch (IllegalArgumentException e) only as a last resort when third-party code calls isAutomatic() unconditionally; log and default to false.
Prevention
- Always pair isNamed() checks before any of isAutomatic()/getName()-dependent logic.
- Wrap module queries in a helper that encodes the unnamed-module policy once.
- Test with classpath-loaded guest classes (unnamed module) in addition to modular ones.
When it happens
Trigger: Calling ResolvedJavaModule.isAutomatic() (directly or via JVMCI/Graal code that queries module descriptors) on a module resolved from a class loaded by the boot/platform or unnamed classloader of the guest Espresso VM — every unnamed module has name == null.
Common situations: Guest code compiled with Espresso where classes sit in the unnamed module (classpath-style loading, modules disabled via --no-modules or legacy mode, or polyglot embedding without module layer setup); Graal compiler phases that probe module-automatic status while walking annotations or services.
Related errors
- Constant has unexpected type
- Element is not an instance of the component type
- Element should be a but was
- Element should be an espresso object constant, got
- Expected a non-void primitive kind, got
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/2db253d6e625af11.
Report an issue: GitHub.
Appendix: source
Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaModule.java:111
return access.java_lang_Module_isExported_String_Module.getMirror().execute(moduleValue, packageNameValue, espressoModule.moduleValue).asBoolean();
}
@Override
public Set<String> getPackages() {
Value packages = access.java_lang_Module_getPackages.getMirror().execute(moduleValue);
return packages.as(new TypeLiteral<>() {
});
}
@Override
public boolean isNamed() {
return name != null;
}
@Override
public boolean isAutomatic() {
if (!isNamed()) {
throw new IllegalArgumentException("Must not call isAutomatic() on an unnamed module");
}
Value moduleDescriptor = access.java_lang_Module_getDescriptor.getMirror().execute(moduleValue);
Value isAutomatic = access.java_lang_module_ModuleDescriptor_isAutomatic.getMirror().execute(moduleDescriptor);
return isAutomatic.asBoolean();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
EspressoExternalResolvedJavaModule that = (EspressoExternalResolvedJavaModule) o;
return moduleValue.equals(that.moduleValue);
}
View on GitHub (pinned to a66e9ccd1d)