{"record":{"id":"2b2b54c72a54a10e","repo":"oracle/graal","slug":"methoddeleted","errorCode":"MethodDeleted","errorMessage":"class redefinition failed: attempted to delete a method","messagePattern":"class redefinition failed: attempted to delete a method","errorType":"error_code","errorClass":"RedefinitionException","httpStatus":null,"severity":"error","filePath":"espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java","lineNumber":576,"sourceCode":"            for (ParserMethod changed : newMethods) {\n                for (int i = 0; i < newParserMethods.length; i++) {\n                    if (newParserMethods[i] == changed) {\n                        collectedChanges.addNewMethod(finalMethods[i]);\n                        break;\n                    }\n                }\n            }\n        } else {\n            collectedChanges.addNewMethods(newMethods);\n        }\n\n        for (Method oldMethod : oldMethods) {\n            collectedChanges.addRemovedMethod(oldMethod.getMethodVersion());\n        }\n\n        if (!oldMethods.isEmpty()) {\n            if (jvmtiRestrictions) {\n                throw new RedefinitionException(RedefinitionError.MethodDeleted);\n            }\n            result = ClassChange.REMOVE_METHOD;\n        } else if (!newMethods.isEmpty()) {\n            if (jvmtiRestrictions) {\n                throw new RedefinitionException(RedefinitionError.MethodAdded);\n            }\n            result = ClassChange.ADD_METHOD;\n        }\n\n        if (isPatched) {\n            result = ClassChange.CLASS_NAME_CHANGED;\n        }\n\n        // detect field changes\n        Field[] oldFields = oldKlass.getDeclaredFields();\n        ParserField[] newFields = newParserKlass.getFields();\n\n        ArrayList<Field> oldFieldsList = new ArrayList<>(Arrays.asList(oldFields));","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java#L558-L594","documentation":"RedefinitionException(RedefinitionError.MethodDeleted) thrown by detectClassChanges when JVMTI restrictions are on and the matching phase leaves old methods unmatched (oldMethods non-empty after pairing), i.e. the replacement class omits at least one method present in the original. Before throwing, the removed methods were recorded via collectedChanges.addRemovedMethod, but under jvmtiRestrictions deletion is fatal.","triggerScenarios":"Restricted redefinition where a method present in the old class has no same-name-and-descriptor counterpart in the new bytes: method removed, renamed, or its signature changed so it no longer matches.","commonSituations":"Deleting a method during development and hotswapping; changing a parameter type so the old descriptor disappears; IDE refactor-rename applied via hot reload; source-level 'unused method' cleanup hitting a running context.","solutions":["Keep every existing method (same name and exact descriptor) in the replacement class; delete methods only across a restart.","If a signature must change, add the new signature while temporarily retaining the old one, then clean up after restart.","Use Espresso unrestricted redefinition (not JVMTI mode) if method removal must be hotswapped."],"exampleFix":"// before: v2 removed `int compute(int)`\n// after: keep both during hotswap\nclass Service {\n    int compute(int x) { return computeLong(x, 0); } // old signature retained\n    long computeLong(int x, long y) { ... }          // new signature added\n}","handlingStrategy":"validation","validationCode":"// diff method sets (name+descriptor) before submitting bytes\nSet<String> oldSigs = methodsOf(oldBytes);\nSet<String> newSigs = methodsOf(newBytes);\nSet<String> deleted = new HashSet<>(oldSigs); deleted.removeAll(newSigs);\nif (!deleted.isEmpty()) {\n    throw new UnsupportedOperationException(\"methods removed, restart required: \" + deleted);\n}","typeGuard":null,"tryCatchPattern":"catch (RedefinitionException e) {\n    if (e.getError() == RedefinitionError.MethodDeleted) { /* restore methods or restart */ }\n}","preventionTips":["In hotswap workflows, only edit method bodies.","Automate a signature-diff check in the reload pipeline to fail fast with a clear message."],"tags":["espresso","hotswap","class-redefinition","jvmti","methods"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}