NationalSecurityAgency/ghidra · error · UnsupportedOperationException

Either delete the root, or modify the type

Error message

Either delete the root, or modify the type

What it means

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.

Solutions

  1. Delete the root data unit instead: component.getRoot().delete() or traceData.delete() on the parent.
  2. 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.
  3. Clear the root data unit and re-apply a new type at the address.

Example fix

// before
for (TraceDataValue component : root.getDataComponents()) {
    component.delete(); // throws
}

// after — delete the root unit, or change its type
root.delete(); // removes the entire composite
// OR: root.getTrace().getMemoryManager().clear... then re-apply a different DataType
Defensive patterns

Strategy: validation

Validate before calling

// Never call delete() on a component; check before deleting
if (dataValue instanceof TraceDataComponent) {
    // Do not call dataValue.delete() — operate on the root instead
    TraceData root = ((TraceDataComponent) dataValue).getRoot();
    root.delete();
} else {
    dataValue.delete();
}

Type guard

static boolean isDataComponent(Object dataValue) {
    return dataValue instanceof TraceDataComponent;
}

// Usage: if (isDataComponent(dv)) { dv.getRoot().delete(); } else { dv.delete(); }

Try / catch

try {
    dataValue.delete();
} catch (UnsupportedOperationException e) {
    if (e.getMessage().contains("delete the root")) {
        // This is a component — delete the root instead
        ((TraceData) dataValue).getTrace().delete(); // or find root
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/f865ca36d57eee81. Report an issue: GitHub.

Appendix: source

Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractDBTraceDataComponent.java:92

		this.address = address;
		this.dataType = dataType;
		this.length = length;

		this.level = parent.getComponentLevel() + 1;
		this.baseDataType = DBTraceData.getBaseDataType(dataType);
		// NOTE: Max address of root will have already overflowed if that were a concern here
		this.maxAddress = address.add(length - 1);
		this.defaultSettings = dataType.getDefaultSettings();
	}

	@Override
	public String toString() {
		return doToString();
	}

	@Override
	public void delete() {
		throw new UnsupportedOperationException("Either delete the root, or modify the type");
	}

	@Override
	public DBTrace getTrace() {
		return root.getTrace();
	}

	@Override
	public TraceThread getThread() {
		return root.getThread();
	}

	@Override
	public TracePlatform getPlatform() {
		return root.getPlatform();
	}

	@Override

View on GitHub (pinned to d5f144c24d)