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

  1. Inspect the exception message (formatted into the RedefinitionException) to identify the exact parse/verification problem.
  2. Regenerate the class bytes with a known-good compiler or verified bytecode tool (javac, ASM with COMPUTE_FRAMES) and retry the redefinition.
  3. Validate the bytes before submitting: parse them with a standalone class-file parser (e.g. ASM ClassReader) to confirm they are well formed.
  4. 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

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.