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.

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)

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.