oracle/graal · error · RedefinitionException
InvalidClassFormat
InvalidClassFormat
Error message
{} What it means
Thrown as RedefinitionException with RedefinitionError.InvalidClassFormat when Espresso's class redefinition (hotswap) pipeline fails to parse the new class bytes: ParserKlassProvider raised a ValidationException or ParserException.ClassFormatError. The '{}' message is the underlying parser message describing the malformed structure. Redefinition aborts before any class changes are applied.
Source
Thrown at espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java:235
ParserKlass parserKlass;
ParserKlass newParserKlass = null;
ClassChange classChange;
DetectedChange detectedChange = new DetectedChange();
StaticObject loader = klass.getDefiningClassLoader();
TypeSymbols typeSymbols = klass.getContext().getTypes();
try {
parserKlass = ParserKlassProvider.parseKlassWithHostErrors(ClassRegistry.ClassDefinitionInfo.EMPTY, context.getClassLoadingEnv(), loader,
typeSymbols.fromClassNameEntry(hotSwapInfo.getName()), bytes);
if (hotSwapInfo.isPatched()) {
byte[] patched = hotSwapInfo.getPatchedBytes();
newParserKlass = parserKlass;
// we detect changes against the patched bytecode
parserKlass = ParserKlassProvider.parseKlassWithHostErrors(ClassRegistry.ClassDefinitionInfo.EMPTY, context.getClassLoadingEnv(), loader,
typeSymbols.fromClassNameEntry(hotSwapInfo.getNewName()),
patched);
}
} catch (ValidationException | ParserException.ClassFormatError validationOrBadFormat) {
throw new RedefinitionException(RedefinitionError.InvalidClassFormat, validationOrBadFormat.getMessage());
} catch (ParserException.UnsupportedClassVersionError unsupportedClassVersionError) {
throw new RedefinitionException(RedefinitionError.UnsupportedVersion, unsupportedClassVersionError.getMessage());
} catch (ParserException.NoClassDefFoundError noClassDefFoundError) {
// see HotSpot VM_RedefineClasses::load_new_class_versions
throw new RedefinitionException(RedefinitionError.NamesDontMatch, noClassDefFoundError.getMessage());
} catch (ParserException parserException) {
throw EspressoError.shouldNotReachHere("Not a validation nor parser exception", parserException);
}
classChange = detectClassChanges(parserKlass, klass, detectedChange, newParserKlass, jvmtiRestrictions);
if (classChange == ClassChange.CLASS_HIERARCHY_CHANGED && detectedChange.getSuperKlass() != null) {
// keep track of unhandled changed super classes
ObjectKlass superKlass = detectedChange.getSuperKlass();
ObjectKlass oldSuperKlass = klass.getSuperKlass();
ObjectKlass commonSuperKlass = (ObjectKlass) oldSuperKlass.findLeastCommonAncestor(superKlass);
while (superKlass != commonSuperKlass) {
superClassChanges.add(superKlass);
superKlass = superKlass.getSuperKlass();
}View on GitHub (pinned to a66e9ccd1d)
Solutions
- Inspect the exception message (formatted into the RedefinitionException) to identify the exact parse/verification problem.
- Regenerate the class bytes with a known-good compiler or verified bytecode tool (javac, ASM with COMPUTE_FRAMES) and retry the redefinition.
- Validate the bytes before submitting: parse them with a standalone class-file parser (e.g. ASM ClassReader) to confirm they are well formed.
- If a patcher/instrumentation agent produced the bytes, disable it or fix its transformer to isolate the source of corruption.
Example fix
// before
byte[] bytes = Files.readAllBytes(Paths.get("NewVersion.class")); // possibly corrupt
redefinition.redefine(klass, bytes);
// after
byte[] bytes = Files.readAllBytes(Paths.get("NewVersion.class"));
try { new org.objectweb.asm.ClassReader(bytes); } // fail fast on malformed bytes
catch (RuntimeException e) { throw new IllegalArgumentException("bad class file", e); }
redefinition.redefine(klass, bytes); Defensive patterns
Strategy: validation
Validate before calling
// sanity-parse replacement bytes before submitting them for redefinition
try {
new org.objectweb.asm.ClassReader(bytes).accept(null, 0);
} catch (RuntimeException e) {
throw new IllegalArgumentException("malformed class file: " + e.getMessage(), e);
} Try / catch
catch (RedefinitionException e) {
if (e.getError() == RedefinitionError.InvalidClassFormat) {
// report, keep old class version running, regenerate bytes
}
} Prevention
- Always round-trip generated bytecode through a parser before hotswap.
- Write class bytes atomically (temp file + rename) to avoid truncated reads.
- Pin bytecode tool versions so transformers stay consistent.
When it happens
Trigger: Calling the redefinition/hotswap API with byte[] that is not a structurally valid class file (truncated bytes, corrupted constant pool, bad magic/major version layout, instrumented bytecode from a broken agent); redefining a patched class whose patched bytes are invalid.
Common situations: Hotswap agents (JRebel-style tools, debuggers, custom instrumentation) producing corrupt or partially-written class files; reading class bytes from a stream that was closed early; a bytecode transformer bug injecting invalid attributes; file-transfer corruption of .class files.
Related errors
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/efad35f67a71e0dd.
Report an issue: GitHub.