oracle/graal · error · RedefinitionException

NamesDontMatch

NamesDontMatch

Error message

{}

What it means

RedefinitionException with RedefinitionError.NamesDontMatch thrown when parsing the replacement class bytes triggers ParserException.NoClassDefFoundError. Following HotSpot's VM_RedefineClasses::load_new_class_versions semantics, a class referenced during parsing (typically a superclass or interface of the new version) could not be found, which surfaces as a names-do-not-match failure. The '{}' is the underlying parser message naming the missing dependency.

Source

Thrown at espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java:240

            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();
                }
            }
            ChangePacket packet = new ChangePacket(hotSwapInfo, newParserKlass != null ? newParserKlass : parserKlass, classChange, detectedChange);
            result.add(packet);
            temp.put(klass, packet);
        }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Ensure the replacement bytes define exactly the same class name as the class being redefined (no renames).
  2. Deploy/load every new superclass or interface referenced by the replacement class before triggering the redefinition.
  3. Check the exception message for the missing type name and add that dependency to the runtime classpath.
  4. If the rename is intentional, use class retransformation with a compatible toolchain or restart the context instead of hotswap.

Example fix

// before: bytes define com.example.NewName but redefining com.example.OldName
redefine(oldNameKlass, new nameBytes);
// after: keep the class name identical in the replacement bytes
redefine(oldNameKlass, sameNameBytes); // bytes must declare com.example.OldName
Defensive patterns

Strategy: validation

Validate before calling

// verify the bytes define the same class you are redefining
String defined = new org.objectweb.asm.ClassReader(bytes).getClassName();
if (!defined.equals(klass.getType().toString().replace('/', '.'))) {
    throw new IllegalArgumentException("bytes define " + defined + ", expected " + klass.getName());
}
// also ensure any new supertype is loadable by the defining loader
for (String supertype : collectSupertypes(bytes)) {
    Class.forName(supertype, false, hostLoaderFor(klass));
}

Try / catch

catch (RedefinitionException e) {
    if (e.getError() == RedefinitionError.NamesDontMatch) { /* deploy missing dependency or fix class name, then retry */ }
}

Prevention

When it happens

Trigger: Submitting hotswap bytes for class A whose new version references a superclass/interface (or the class name itself differs from the class being redefined) that is not loadable by the defining class loader; redefining a class with bytes compiled from a renamed source file.

Common situations: Refactoring that renames a class while a hotswap tool still submits old/new name pairs; adding an interface or superclass in the new version that is not on the runtime classpath; multi-module builds where the dependency containing the new supertype was not deployed before the swap.

Related errors


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