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

  1. Hotswap only changes to existing method bodies; introduce new methods via a restart or unrestricted redefinition.
  2. If the new method is needed immediately, refactor so existing methods delegate to a new helper class that can be freshly loaded.
  3. 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

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.