{"record":{"id":"f865ca36d57eee81","repo":"NationalSecurityAgency/ghidra","slug":"either-delete-the-root-or-modify-the-type","errorCode":null,"errorMessage":"Either delete the root, or modify the type","messagePattern":"Either delete the root, or modify the type","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractDBTraceDataComponent.java","lineNumber":92,"sourceCode":"\t\tthis.address = address;\n\t\tthis.dataType = dataType;\n\t\tthis.length = length;\n\n\t\tthis.level = parent.getComponentLevel() + 1;\n\t\tthis.baseDataType = DBTraceData.getBaseDataType(dataType);\n\t\t// NOTE: Max address of root will have already overflowed if that were a concern here\n\t\tthis.maxAddress = address.add(length - 1);\n\t\tthis.defaultSettings = dataType.getDefaultSettings();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn doToString();\n\t}\n\n\t@Override\n\tpublic void delete() {\n\t\tthrow new UnsupportedOperationException(\"Either delete the root, or modify the type\");\n\t}\n\n\t@Override\n\tpublic DBTrace getTrace() {\n\t\treturn root.getTrace();\n\t}\n\n\t@Override\n\tpublic TraceThread getThread() {\n\t\treturn root.getThread();\n\t}\n\n\t@Override\n\tpublic TracePlatform getPlatform() {\n\t\treturn root.getPlatform();\n\t}\n\n\t@Override","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractDBTraceDataComponent.java#L74-L110","documentation":"Thrown by AbstractDBTraceDataComponent.delete() because a data component (a sub-field within a composite data unit, e.g., a struct member) cannot be independently deleted. Data components are derived from their parent data unit's data type definition — deleting a component makes no sense because the component's existence is governed by the root data unit's type. To remove a component you must either delete the entire root data unit or change the root unit's data type to one that no longer has that component.","triggerScenarios":"Calling component.delete() on a TraceDataComponent object obtained from a composite/array data unit — e.g., iterating getDataComponents() and calling delete() on an individual member.","commonSituations":"Treating data components like top-level code units; scripting that iterates struct members and tries to remove individual members; misunderstanding the component/root relationship in Ghidra's trace data model.","solutions":["Delete the root data unit instead: component.getRoot().delete() or traceData.delete() on the parent.","If you want to keep the unit but change its structure, modify the root's data type via setData() or replace it with a different DataType.","Clear the root data unit and re-apply a new type at the address."],"exampleFix":"// before\nfor (TraceDataValue component : root.getDataComponents()) {\n    component.delete(); // throws\n}\n\n// after — delete the root unit, or change its type\nroot.delete(); // removes the entire composite\n// OR: root.getTrace().getMemoryManager().clear... then re-apply a different DataType","handlingStrategy":"validation","validationCode":"// Never call delete() on a component; check before deleting\nif (dataValue instanceof TraceDataComponent) {\n    // Do not call dataValue.delete() — operate on the root instead\n    TraceData root = ((TraceDataComponent) dataValue).getRoot();\n    root.delete();\n} else {\n    dataValue.delete();\n}","typeGuard":"static boolean isDataComponent(Object dataValue) {\n    return dataValue instanceof TraceDataComponent;\n}\n\n// Usage: if (isDataComponent(dv)) { dv.getRoot().delete(); } else { dv.delete(); }","tryCatchPattern":"try {\n    dataValue.delete();\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage().contains(\"delete the root\")) {\n        // This is a component — delete the root instead\n        ((TraceData) dataValue).getTrace().delete(); // or find root\n    } else {\n        throw e;\n    }\n}","preventionTips":["Never call delete() on data components — always operate on the root data unit.","Distinguish TraceData (root, deletable) from TraceDataComponent (derived, not deletable) in your code.","When iterating data components, collect their root units for batch deletion."],"tags":["data-component","delete","composite-data","trace-modeling"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}