NationalSecurityAgency/ghidra · error · LSHException

Id mismatch when inserting executable:

Error message

Id mismatch when inserting executable: 

What it means

In `testExecutableDuplication`, when an incoming executable's metadata matches an existing record, but the incoming record already carries a rowId that differs from the stored one, LSHException is thrown. Equal metadata with disagreeing IDs signals inconsistent state that would corrupt cross-table linkage, so the insert is refused.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/AbstractSQLFunctionDatabase.java:1059

	private void testExecutableDuplication(DescriptionManager input)
			throws SQLException, LSHException, DatabaseNonFatalException {
		boolean pickout_storedfuncs = false;
		for (ExecutableRecord erec : input.getExecutableRecordSet()) {
			ExecutableRow row = exeTable.queryMd5ExeMatch(erec.getMd5());
			if (row != null) { // Already have a matching executable
				ExecutableRecord tmp = makeExecutableRecordTemp(row);
				int cmp = tmp.compareMetadata(erec);
				if (cmp != 0) {
					String fatalerror = FunctionDatabase.constructFatalError(cmp, erec, tmp);
					if (fatalerror != null) {
						throw new LSHException(fatalerror);
					}
					throw new DatabaseNonFatalException(
						FunctionDatabase.constructNonfatalError(cmp, erec, tmp));
				}
				if (erec.getRowId() != null) {
					if (!erec.getRowId().equals(tmp.getRowId())) {
						throw new LSHException(
							"Id mismatch when inserting executable: " + erec.getNameExec());
					}
				}
				else {
					input.setExeRowId(erec, tmp.getRowId());
				}
				input.setExeAlreadyStored(erec);
				// Just because we've seen a library before doesn't mean we should stop function insertion
				// Libraries are likely to be partially inserted multiple times
				if (!erec.isLibrary()) {
					throw new DatabaseNonFatalException(
						erec.getNameExec() + " is already ingested");
				}
				pickout_storedfuncs = true; // At least one executable has previously inserted functions
			}
		}

		if (pickout_storedfuncs) {

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Restart the ingest with a fresh DescriptionManager carrying no pre-set rowIds.
  2. Avoid concurrent ingests writing the same DB; serialize writers.
  3. Verify DB integrity and confirm no partial-state rows remain.
Defensive patterns

Strategy: validation

Validate before calling

// Ensure incoming executables carry NO pre-set rowId before insert.
for (ExecutableRecord erec : manager.getAllExecutables()) {
    if (erec.getRowId() != null) {
        throw new IllegalStateException(
            "Input executable has pre-set rowId; rebuild DescriptionManager: " + erec.getNameExec());
    }
}

Try / catch

try {
    db.insert(manager);
} catch (LSHException e) {
    if (e.getMessage().startsWith("Id mismatch when inserting executable:")) {
        // inconsistent state -- abort the batch and restart with a clean manager
        throw new IngestStateInconsistentException(e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Re-inserting an executable through a path that pre-assigned a rowId different from the DB's -- typically concurrent/cross-connection inserts sharing a DescriptionManager, or resuming an aborted ingest with stale ID assignments.

Common situations: Parallel ingest processes against the same DB; reusing a DescriptionManager across databases; DB restored from a partial/inconsistent backup; idempotent-retry logic that preserved IDs.

Related errors


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