{"record":{"id":"6a360bf5b83e81fe","repo":"NationalSecurityAgency/ghidra","slug":"overwriting-existing-executable-id","errorCode":null,"errorMessage":"Overwriting existing executable id","messagePattern":"Overwriting existing executable id","errorType":"exception","errorClass":"LSHException","httpStatus":null,"severity":"error","filePath":"Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/description/DescriptionManager.java","lineNumber":235,"sourceCode":"\t * @param arc is the architecture of the executable\n\t * @param dt is the date (of ingest)\n\t * @param repo is the repository containing the executable\n\t * @param path is the path (within the repo) to the executable\n\t * @param id is the database (row) is associated with the executable (may be null)\n\t * @return the new ExecutableRecord object\n\t * @throws LSHException if attributes are invalid, or the executable \n\t *     already exists with different metadata\n\t */\n\tpublic ExecutableRecord newExecutableRecord(String md5, String enm, String cnm, String arc,\n\t\t\tDate dt, String repo, String path, RowKey id) throws LSHException {\n\t\tExecutableRecord newexe = new ExecutableRecord(md5, enm, cnm, arc, dt, id, repo, path);\n\t\tif (!exerec.add(newexe)) {\n\t\t\tExecutableRecord oldexe = exerec.floor(newexe);\n\t\t\tif (oldexe.compareMetadata(newexe) != 0) {\n\t\t\t\tthrow new LSHException(\"Duplicate md5 hash, different metadata\");\n\t\t\t}\n\t\t\tif ((oldexe.getRowId() != null) && (id != null) && (!oldexe.getRowId().equals(id))) {\n\t\t\t\tthrow new LSHException(\"Overwriting existing executable id\");\n\t\t\t}\n\t\t\tnewexe = oldexe;\n\t\t}\n\t\treturn newexe;\n\t}\n\n\t/**\n\t * Create a new \"library\" executable in the container.\n\t * Functions in this container (will) have no body or address\n\t * @param enm is the name of the library\n\t * @param arc is the architecture of the library\n\t * @param id is the database id associated with the library (may be null)\n\t * @return the new ExecutableRecord object\n\t * @throws LSHException if attributes are invalid or the\n\t *   library already exists with different metadata\n\t */\n\tpublic ExecutableRecord newExecutableLibrary(String enm, String arc, RowKey id)\n\t\t\tthrows LSHException {","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/description/DescriptionManager.java#L217-L253","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ndescMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, newId);\n// throws: existing record already has a different id\n\n// after\nExecutableRecord existing = descMgr.getExecutableRecord(md5);\nRowKey idToUse = (existing != null) ? existing.getRowId() : newId;\n// pass null to preserve existing id, or the canonical id\ndescMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, existing != null ? null : newId);","handlingStrategy":"validation","validationCode":"// Reuse the existing row id instead of passing a conflicting new one.\nExecutableRecord existing = descMgr.findExecutableByMd5(md5);\nRowKey idToPass = (existing != null && existing.getRowId() != null) ? null : id;\nreturn descMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, idToPass);","typeGuard":null,"tryCatchPattern":"try {\n    return descMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, id);\n} catch (LSHException e) {\n    if (e.getMessage().contains(\"Overwriting existing executable id\")) {\n        // retry preserving the existing id\n        ExecutableRecord ex = descMgr.findExecutableByMd5(md5);\n        return descMgr.newExecutableRecord(md5, name, comp, arch, date, repo, path, null);\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["bsim","metadata","duplicate-md5","row-id-conflict","validation","lsh-exception"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}