oracle/graal · error · EspressoClassLoadingException.ClassCircularityError
Class circularity detected
Error message
Class circularity detected
What it means
EspressoClassLoadingException.ClassCircularityError is thrown (with fixed message 'Class circularity detected') when class initialization or loading detects that a class is (transitively) its own superclass/superinterface, or a loading loop among classes. It mirrors the JVM's ClassCircularityError and is later converted to the guest error of the same name.
Source
Thrown at espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EspressoClassLoadingException.java:42
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
import com.oracle.truffle.espresso.classfile.descriptors.Type;
import com.oracle.truffle.espresso.classfile.descriptors.TypeSymbols;
import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.EspressoException;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
/**
* Indicates an exception that occurred during class loading.
*/
public abstract class EspressoClassLoadingException extends Exception {
private static final long serialVersionUID = 1598679948708713831L;
public static EspressoClassLoadingException.ClassCircularityError classCircularityError() throws EspressoClassLoadingException.ClassCircularityError {
CompilerDirectives.transferToInterpreter();
throw new EspressoClassLoadingException.ClassCircularityError("Class circularity detected");
}
public static EspressoClassLoadingException.IncompatibleClassChangeError incompatibleClassChangeError(String msg) throws EspressoClassLoadingException.IncompatibleClassChangeError {
CompilerDirectives.transferToInterpreter();
throw new EspressoClassLoadingException.IncompatibleClassChangeError(msg);
}
public static EspressoClassLoadingException.SecurityException securityException(String msg) throws EspressoClassLoadingException.SecurityException {
CompilerDirectives.transferToInterpreter();
throw new EspressoClassLoadingException.SecurityException(msg);
}
public static EspressoClassLoadingException.LinkageError linkageError(String msg) throws EspressoClassLoadingException.LinkageError {
CompilerDirectives.transferToInterpreter();
throw new EspressoClassLoadingException.LinkageError(msg);
}
public static EspressoClassLoadingException.IllegalAccessError illegalAccessError(String msg) throws EspressoClassLoadingException.IllegalAccessError {View on GitHub (pinned to a66e9ccd1d)
Solutions
- Dump the class hierarchy of the involved classes (javap -v shows super/interfaces) and break the cycle.
- If classes were generated or transformed by your tooling, regenerate with consistent hierarchy metadata.
- If the input classes load fine on a standard JVM, file a GraalVM/Espresso issue with the reproducing jars.
- Retry with parallel class loading disabled / single-threaded context to rule out a race in the loading state machine.
Defensive patterns
Strategy: try-catch
Try / catch
try {
meta.loadKlass(type, definingLoader, StaticObject.NULL);
} catch (EspressoClassLoadingException.ClassCircularityError e) {
// surface which class closed the cycle; the class set must be fixed, retrying will not help
} Prevention
- Validate generated hierarchies are acyclic before loading.
- Do not hand-edit super_class / interfaces indices in class files.
- If classes load fine on a reference JVM, report the Espresso discrepancy with the jars.
When it happens
Trigger: A guest class hierarchy where A extends B and B extends A, a class listed as its own superinterface, or initialization cycles detected during Espresso's load/resolve of the chain. Espresso invokes this factory from its class-loading state machine when the circularity invariant trips.
Common situations: Bytecode generators or hot-reload tools producing cyclic hierarchies; obfuscated or hand-crafted class files with self-referential super_class indices; bugs in Espresso's lazy loading order when loading heavily-interdependent classes in parallel.
Related errors
- No ClassConstant at constant pool index ${cpi}
- NamesDontMatch
- Loading constraint violated !
- New loading constraint violates an older one!
- Cannot bind label to negative position %d
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/533bf20b6a3d3afd.
Report an issue: GitHub.