oracle/graal · error · RedefinitionException
MethodAdded
MethodAdded
Error message
class redefinition failed: attempted to add a method
What it means
RedefinitionException(RedefinitionError.MethodAdded) thrown by detectClassChanges under JVMTI restrictions when the new class declares methods that did not match any old method (newMethods non-empty after pairing). JVMTI class redefinition may not add methods, only replace bodies of existing ones; the added methods were recorded as new methods before the guard fires.
Source
Thrown at espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java:581
}
}
}
} else {
collectedChanges.addNewMethods(newMethods);
}
for (Method oldMethod : oldMethods) {
collectedChanges.addRemovedMethod(oldMethod.getMethodVersion());
}
if (!oldMethods.isEmpty()) {
if (jvmtiRestrictions) {
throw new RedefinitionException(RedefinitionError.MethodDeleted);
}
result = ClassChange.REMOVE_METHOD;
} else if (!newMethods.isEmpty()) {
if (jvmtiRestrictions) {
throw new RedefinitionException(RedefinitionError.MethodAdded);
}
result = ClassChange.ADD_METHOD;
}
if (isPatched) {
result = ClassChange.CLASS_NAME_CHANGED;
}
// detect field changes
Field[] oldFields = oldKlass.getDeclaredFields();
ParserField[] newFields = newParserKlass.getFields();
ArrayList<Field> oldFieldsList = new ArrayList<>(Arrays.asList(oldFields));
ArrayList<ParserField> newFieldsList = new ArrayList<>(Arrays.asList(newFields));
Map<ParserField, Field> compatibleFields = new HashMap<>();
Iterator<Field> oldFieldsIt = oldFieldsList.iterator();
Iterator<ParserField> newFieldsIt;View on GitHub (pinned to a66e9ccd1d)
Solutions
- Hotswap only changes to existing method bodies; introduce new methods via a restart or unrestricted redefinition.
- If the new method is needed immediately, refactor so existing methods delegate to a new helper class that can be freshly loaded.
- Configure the reload toolchain to use Espresso's non-JVMTI redefinition mode, which supports adding methods.
Example fix
// before: hotswap adds newMethod() to existing class -> rejected
// after: put new logic in a new class loaded fresh
class ServicePlugin { // new class, loaded (not redefined)
static void newMethod() { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// detect newly added methods before hotswap
Set<String> added = new HashSet<>(methodsOf(newBytes)); added.removeAll(methodsOf(oldBytes));
if (!added.isEmpty()) {
throw new UnsupportedOperationException("methods added, restart required: " + added);
} Try / catch
catch (RedefinitionException e) {
if (e.getError() == RedefinitionError.MethodAdded) { /* restart or use unrestricted mode */ }
} Prevention
- Route new functionality through freshly loaded classes instead of edited ones.
- Know which redefinition mode your reload tool uses; JVMTI mode never adds methods.
When it happens
Trigger: Restricted redefinition where the replacement bytes contain a method (new name or new descriptor) absent from the original class.
Common situations: Writing new methods/features during development and expecting hotswap to pick them up; overloads added with new parameter lists; generated code (Lombok, annotation processors) adding methods between builds.
Related errors
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/ebaff7b0528c03b1.
Report an issue: GitHub.