NationalSecurityAgency/ghidra · critical · IOException

Data table is corrupt. Data unit and its datatype disagree o

Error message

Data table is corrupt. Data unit and its datatype disagree on length.

What it means

Thrown by DBTraceData.fresh() when the data type's length (getDataTypeLength()) does not equal the stored range length, and the data type length is not -1 (variable-length). This means the persisted data unit's byte range and its data type's expected size disagree — a sign of internal inconsistency in the trace database. The unit cannot be safely interpreted because the type boundary and the recorded address range do not match.

Source

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

	@Override
	protected void fresh(boolean created) throws IOException {
		super.fresh(created);
		if (created) {
			return;
		}
		platform = space.manager.platformManager.getPlatformByKey(platformKey);
		if (platform == null) {
			throw new IOException("Data table is corrupt. Missing platform: " + platformKey);
		}
		dataType = platform.getDataTypeManager().getDataType(dataTypeID);
		if (dataType == null) {
			throw new IOException("Data table is corrupt. Missing datatype: " + dataTypeID);
		}
		baseDataType = getBaseDataType(dataType);
		final int dtLen = getDataTypeLength();
		if (dtLen != range.getLength() && dtLen != -1) {
			throw new IOException(
				"Data table is corrupt. Data unit and its datatype disagree on length.");
		}
		defaultSettings = dataType.getDefaultSettings();
	}

	@Override
	protected void setRecordValue(DBTraceData value) {
		// Nothing. Entry is the value
	}

	@Override
	protected DBTraceData getRecordValue() {
		return this;
	}

	/**
	 * Set the fields of this record
	 * 

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Ensure the data type definitions (structs, enums, etc.) are identical between trace creation and trace loading — load the same archives.
  2. Restore from a backup where the type definitions and trace data are consistent.
  3. If intentional type changes were made, re-apply the data types to the affected addresses after opening, or recreate the trace data units.

Example fix

// before — trace opens, struct size changed from 8 to 12
// throws IOException: Data unit and its datatype disagree on length

// after — load matching type archive before opening the trace
// Ensure the struct definition in the loaded archive matches the
// one used when the trace was created (same field layout / size).
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot pre-validate individual records; ensure type consistency at archive level
// Verify data type sizes match between the loaded archive and what the trace expects:
DataType dt = dtm.getDataType(categoryPath, name);
if (dt != null && expectedLength != dt.getLength()) {
    Msg.warn(MyClass.class, "Type size mismatch for " + name);
}

Try / catch

try {
    trace = dbTrace.openForReading(path);
} catch (IOException e) {
    if (e.getMessage().contains("disagree on length")) {
        Msg.error(MyClass.class, "Trace data/type length mismatch: " + e.getMessage());
        // Restore from backup or load matching type definitions
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Loading a trace where a DBTraceData record's range.getLength() differs from the resolved DataType's length. For example, a 4-byte integer type stored over a 8-byte address range, or a struct that was resized after the unit was written.

Common situations: Data type definition changed size between writing and reading the trace (e.g., a struct had a field added); partial write due to crash; manual database tampering; version mismatch in built-in type definitions.

Related errors


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