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
- Restart the ingest with a fresh DescriptionManager carrying no pre-set rowIds.
- Avoid concurrent ingests writing the same DB; serialize writers.
- 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
- Use a single writer (serialize ingests) against a given DB.
- Never reuse a DescriptionManager across databases or resumed sessions with stale IDs.
- Treat ID mismatch as corruption and restart the ingest batch cleanly.
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
- is already ingested
- Already inserted
- No functions matching vectorid:
- No functions matching vectorid: {vecResult.vectorid}
- Trying to insert on read-only database
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/9ebcff3d79506944.
Report an issue: GitHub.