{"record":{"id":"decd509afb3374de","repo":"oracle/graal","slug":"hierarchychanged","errorCode":"HierarchyChanged","errorMessage":"class redefinition failed: attempted to change superclass or interfaces","messagePattern":"class redefinition failed: attempted to change superclass or interfaces","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":678,"sourceCode":"            collectedChanges.addRemovedFields(oldFieldsList);\n            result = ClassChange.SCHEMA_CHANGE;\n        }\n\n        // detect class-level changes\n        if (newParserKlass.getFlags() != oldParserKlass.getFlags()) {\n            if (jvmtiRestrictions) {\n                throw new RedefinitionException(RedefinitionError.ClassModifiersChanged);\n            }\n            result = ClassChange.SCHEMA_CHANGE;\n        }\n\n        collectedChanges.addCompatibleFields(compatibleFields);\n\n        // detect changes to superclass and implemented interfaces\n        Klass superKlass = oldKlass.getSuperKlass();\n        if (!newParserKlass.getSuperKlass().equals(oldParserKlass.getSuperKlass())) {\n            if (jvmtiRestrictions) {\n                throw new RedefinitionException(RedefinitionError.HierarchyChanged);\n            }\n            result = ClassChange.CLASS_HIERARCHY_CHANGED;\n            superKlass = getLoadedKlass(newParserKlass.getSuperKlass(), oldKlass);\n        }\n        collectedChanges.addSuperKlass((ObjectKlass) superKlass);\n\n        ObjectKlass[] newSuperInterfaces = oldKlass.getSuperInterfaces();\n        if (!Arrays.equals(newParserKlass.getSuperInterfaces(), oldParserKlass.getSuperInterfaces())) {\n            if (jvmtiRestrictions) {\n                throw new RedefinitionException(RedefinitionError.HierarchyChanged);\n            }\n            result = ClassChange.CLASS_HIERARCHY_CHANGED;\n            newSuperInterfaces = new ObjectKlass[newParserKlass.getSuperInterfaces().length];\n            for (int i = 0; i < newParserKlass.getSuperInterfaces().length; i++) {\n                newSuperInterfaces[i] = (ObjectKlass) getLoadedKlass(newParserKlass.getSuperInterfaces()[i], oldKlass);\n            }\n        }\n        collectedChanges.addSuperInterfaces(newSuperInterfaces);","sourceCodeStart":660,"sourceCodeEnd":696,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/redefinition/ClassRedefinition.java#L660-L696","documentation":"RedefinitionException(RedefinitionError.HierarchyChanged) thrown under JVMTI restrictions when the replacement class's superclass symbol differs from the original's (newParserKlass.getSuperKlass() vs oldParserKlass.getSuperKlass()). Changing the superclass reshapes the hierarchy; JVMTI redefinition forbids it, while unrestricted mode would proceed to CLASS_HIERARCHY_CHANGED handling.","triggerScenarios":"Restricted hotswap where the new bytes extend a different class (superclass swapped, added, or changed from java.lang.Object to a user class).","commonSituations":"Introducing a base class into an existing hierarchy during refactoring and hotswapping the child; framework-generated subclasses changing parents between builds; copy-paste development changing extends clauses.","solutions":["Keep the same superclass in hotswapped versions; hierarchy edits require a restart.","Load the modified class as a brand-new class name instead of redefining the existing one.","Use unrestricted Espresso redefinition when superclass changes must be hotswapped."],"exampleFix":"// before: `class Task` -> hotswap as `class Task extends BaseTask`\n// after: keep `class Task` for hotswap; introduce hierarchy on restart","handlingStrategy":"validation","validationCode":"String oldSuper = superNameOf(oldBytes);\nString newSuper = superNameOf(newBytes);\nif (!Objects.equals(oldSuper, newSuper)) {\n    throw new UnsupportedOperationException(\"superclass changed from \" + oldSuper + \" to \" + newSuper + \"; restart required\");\n}","typeGuard":null,"tryCatchPattern":"catch (RedefinitionException e) {\n    if (e.getError() == RedefinitionError.HierarchyChanged) { /* restart context */ }\n}","preventionTips":["Refactor hierarchy changes with a restart, not hotswap.","Load structurally different classes under new names."],"tags":["espresso","hotswap","class-redefinition","jvmti","hierarchy"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}