NationalSecurityAgency/ghidra · error · LSHException
Overwriting existing executable id
Error message
Overwriting existing executable id
What it means
Thrown by DescriptionManager.newExecutableRecord when an executable with the same md5 and matching metadata already exists, but both the existing and new records carry non-null, differing row ids. Same binary, same metadata, but conflicting database row ids — the manager refuses to overwrite the existing id, as that would break references to the stored row.
Source
Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/description/DescriptionManager.java:235
* @param arc is the architecture of the executable
* @param dt is the date (of ingest)
* @param repo is the repository containing the executable
* @param path is the path (within the repo) to the executable
* @param id is the database (row) is associated with the executable (may be null)
* @return the new ExecutableRecord object
* @throws LSHException if attributes are invalid, or the executable
* already exists with different metadata
*/
public ExecutableRecord newExecutableRecord(String md5, String enm, String cnm, String arc,
Date dt, String repo, String path, RowKey id) throws LSHException {
ExecutableRecord newexe = new ExecutableRecord(md5, enm, cnm, arc, dt, id, repo, path);
if (!exerec.add(newexe)) {
ExecutableRecord oldexe = exerec.floor(newexe);
if (oldexe.compareMetadata(newexe) != 0) {
throw new LSHException("Duplicate md5 hash, different metadata");
}
if ((oldexe.getRowId() != null) && (id != null) && (!oldexe.getRowId().equals(id))) {
throw new LSHException("Overwriting existing executable id");
}
newexe = oldexe;
}
return newexe;
}
/**
* Create a new "library" executable in the container.
* Functions in this container (will) have no body or address
* @param enm is the name of the library
* @param arc is the architecture of the library
* @param id is the database id associated with the library (may be null)
* @return the new ExecutableRecord object
* @throws LSHException if attributes are invalid or the
* library already exists with different metadata
*/
public ExecutableRecord newExecutableLibrary(String enm, String arc, RowKey id)
throws LSHException {View on GitHub (pinned to d5f144c24d)
Solutions
- Before re-adding, reuse the existing ExecutableRecord (and its row id) instead of supplying a new id — pass the existing id or null.
- When merging DescriptionManagers, canonicalize each md5 to a single row id and update all references.
- Pass null for the id parameter when you want the manager to keep the existing record's id.
- Audit the pipeline to ensure a given md5 is only persisted once with one stable id.
Example fix
// before descMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, newId); // throws: existing record already has a different id // after ExecutableRecord existing = descMgr.getExecutableRecord(md5); RowKey idToUse = (existing != null) ? existing.getRowId() : newId; // pass null to preserve existing id, or the canonical id descMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, existing != null ? null : newId);
Defensive patterns
Strategy: validation
Validate before calling
// Reuse the existing row id instead of passing a conflicting new one. ExecutableRecord existing = descMgr.findExecutableByMd5(md5); RowKey idToPass = (existing != null && existing.getRowId() != null) ? null : id; return descMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, idToPass);
Try / catch
try {
return descMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, id);
} catch (LSHException e) {
if (e.getMessage().contains("Overwriting existing executable id")) {
// retry preserving the existing id
ExecutableRecord ex = descMgr.findExecutableByMd5(md5);
return descMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, null);
}
throw e;
} Prevention
- Pass null for the id when re-adding a known md5 to preserve the existing id.
- Canonicalize each md5 to a single row id when merging DescriptionManagers.
- Persist each md5 exactly once with one stable id.
When it happens
Trigger: Calling newExecutableRecord where the md5+metadata match an existing record, oldexe.getRowId() is non-null, the new id is non-null, and the two ids are not equal. Occurs when loading the same executable from two database sources/queries that assigned different row ids, or when re-inserting an already-persisted record with a freshly generated id.
Common situations: Merging two DescriptionManagers loaded from different databases where the same binary got different row ids. Re-describing a binary after it was already inserted, passing a new generated id while the old one is retained. Inconsistent id tracking in an ingest pipeline that re-assigns ids.
Related errors
- Duplicate md5 hash, different metadata
- Bad category tag
- Executable
- Expecting privilege option (admin or user)
- host required
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/6a360bf5b83e81fe.
Report an issue: GitHub.