oracle/graal · error · IllegalArgumentException

Constant has unexpected type {}: {}

Error message

Constant has unexpected type {}: {}

What it means

Thrown by the EspressoExternalResolvedJavaModule constructor when the polyglot Value passed in is not an instance of guest java.lang.Module (checked via getMetaObject().getMetaQualifiedName()). The adapter dereferences the Value's meta-object immediately and builds a ResolvedJavaModule wrapper around it, so a Value of any other guest type (Class, ModuleLayer, String, null-meta foreign object) fails construction. This guards the boundary where arbitrary interop Values enter the JVMCI type system.

Source

Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaModule.java:44

import java.util.Objects;
import java.util.Set;

import org.graalvm.polyglot.TypeLiteral;
import org.graalvm.polyglot.Value;

import jdk.graal.compiler.vmaccess.ResolvedJavaModule;
import jdk.graal.compiler.vmaccess.ResolvedJavaModuleLayer;

final class EspressoExternalResolvedJavaModule implements ResolvedJavaModule {
    private final EspressoExternalVMAccess access;
    private final String name;
    final Value moduleValue;

    EspressoExternalResolvedJavaModule(EspressoExternalVMAccess access, Value moduleValue) {
        // j.l.Module?
        if (!"java.lang.Module".equals(moduleValue.getMetaObject().getMetaQualifiedName())) {
            throw new IllegalArgumentException("Constant has unexpected type " + moduleValue.getMetaObject().getMetaQualifiedName() + ": " + moduleValue);
        }
        this.access = access;
        this.moduleValue = moduleValue;
        this.name = access.java_lang_Module_getName.getMirror().execute(moduleValue).asString();
    }

    @Override
    public ResolvedJavaModuleLayer getLayer() {
        Value layer = moduleValue.invokeMember("getLayer");
        return layer.isNull() ? null : new EspressoExternalResolvedJavaModuleLayer(access, layer);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Check value.getMetaObject().getMetaQualifiedName().equals("java.lang.Module") before constructing/looking up the module
  2. Handle null meta-object (foreign/host Values) by mapping the object into the Espresso guest context first
  3. If the Value came from getLayer()/ModuleLayer APIs, unwrap the actual module members instead of passing the layer

Example fix

// before
ResolvedJavaModule m = access.findModule(someValue);

// after
if (someValue.getMetaObject() == null ||
    !"java.lang.Module".equals(someValue.getMetaObject().getMetaQualifiedName())) {
    throw new IllegalArgumentException("not a guest java.lang.Module: " + someValue);
}
ResolvedJavaModule m = access.findModule(someValue);
Defensive patterns

Strategy: type-guard

Validate before calling

Value meta = moduleValue.getMetaObject();
if (meta == null || !"java.lang.Module".equals(meta.getMetaQualifiedName())) {
    throw new IllegalArgumentException("not a guest java.lang.Module: " + moduleValue);
}

Type guard

boolean isGuestModule(Value v) {
    Value meta = v.getMetaObject();
    return meta != null && "java.lang.Module".equals(meta.getMetaQualifiedName());
}

Prevention

When it happens

Trigger: Calling whatever API produced this wrapper (module lookup in EspressoExternalVMAccess) with a Value obtained from a Class.getModule() on a primitive/array class, a ModuleLayer Value, or a host object mapped with asValue(...) that has a host meta-object with a different qualified name.

Common situations: Module-aware lookups over classes loaded by the bootstrap loader (unnamed module handling), polyglot context configuration where host meta-objects differ from guest ones, and version changes in how the access layer resolves modules.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/4dad823cf20584ae. Report an issue: GitHub.