{"record":{"id":"036572e9bd256990","repo":"NationalSecurityAgency/ghidra","slug":"didn-t-remove-external-library-libname-since-it","errorCode":null,"errorMessage":"Didn't remove external library {libName} since it isn't empty.","messagePattern":"Didn't remove external library (.+?) since it isn't empty\\.","errorType":"validation","errorClass":"InvalidInputException","httpStatus":null,"severity":"warning","filePath":"Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalProgramMerger.java","lineNumber":581,"sourceCode":"\t\tif (s != null) {\n\t\t\treturn (s.getSource() == SourceType.USER_DEFINED);\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Removes the indicated external library from the indicated program version\n\t * if it is empty.\n\t * @param program the program\n\t * @param libName the external library name\n\t * @throws InvalidInputException if there is no such enterrnal library in the program\n\t */\n\tprivate void removeExternalLibrary(Program program, String libName)\n\t\t\tthrows InvalidInputException {\n\t\tExternalManager extMgr = program.getExternalManager();\n\t\tExternalLocationIterator iter = extMgr.getExternalLocations(libName);\n\t\tif (iter.hasNext()) {\n\t\t\tthrow new InvalidInputException(\n\t\t\t\t\"Didn't remove external library \" + libName + \" since it isn't empty.\");\n\t\t}\n\t\tif (!extMgr.removeExternalLibrary(libName)) {\n\t\t\tthrow new InvalidInputException(\"Didn't remove external library \" + libName);\n\t\t}\n\t}\n\n\t/**\n\t * Determines whether the latest external program name and my external program name are equals.\n\t * @param latestName the latest external program name or null.\n\t * @param myName my external program name or null.\n\t * @return true if the names are equal.\n\t */\n\tprivate boolean same(String latestName, String myName) {\n\t\treturn SystemUtilities.isEqual(latestName, myName);\n\t}\n\n\t/**","sourceCodeStart":563,"sourceCodeEnd":599,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalProgramMerger.java#L563-L599","documentation":"Thrown by ExternalProgramMerger.removeExternalLibrary when an external library still has external locations referencing it. The merger's policy is to only remove empty libraries; iter.hasNext() returning true means at least one ExternalLocation remains, so removal is aborted and InvalidInputException is raised. This protects against orphaning external location references during a merge.","triggerScenarios":"During a multi-user program merge (version-control check-in), the merger attempts to remove an external library (because latest or 'my' version dropped it) but the result program still has external locations pointing into that library. Triggered by autoMergeWhenOnlyLatestChanged / autoMergeWhenOnlyMyChanged when latestName or myName is null.","commonSituations":"One branch deleted a library while another branch (or the result) still references its locations. Merge of programs where external locations were added but the library was simultaneously renamed/removed. Re-entrant merge state.","solutions":["Remove or relocate the external locations in the library before attempting to remove the library.","Keep the library instead of removing it; the exception is informational - catch it and append the message to infoBuf (as the merger's callers already do).","Resolve the merge conflict in the GUI so the library/locations are consistent before check-in.","In scripting, call extMgr.getExternalLocations(libName) first and only remove when iter is empty."],"exampleFix":"// before\nremoveExternalLibrary(program, libName);\n// library has locations -> InvalidInputException\n\n// after\nExternalManager extMgr = program.getExternalManager();\nif (!extMgr.getExternalLocations(libName).hasNext()) {\n    extMgr.removeExternalLibrary(libName);\n} else {\n    infoBuf.append(\"Library \" + libName + \" not removed: still has external locations\\n\");\n}","handlingStrategy":"validation","validationCode":"ExternalManager extMgr = program.getExternalManager();\nboolean empty = !extMgr.getExternalLocations(libName).hasNext();\nif (!empty) {\n    // do not call removeExternalLibrary; relocate or keep the library\n}","typeGuard":"boolean isExternalLibraryEmpty(Program p, String libName) {\n    return !p.getExternalManager().getExternalLocations(libName).hasNext();\n}","tryCatchPattern":"try {\n    removeExternalLibrary(program, libName);\n} catch (InvalidInputException e) {\n    if (e.getMessage().contains(\"isn't empty\")) {\n        // keep the library; log and continue\n        infoBuf.append(e.getMessage() + \"\\n\");\n    } else throw e;\n}","preventionTips":["Check getExternalLocations(libName).hasNext() before removing a library.","Remove or relocate external locations first.","Resolve library/location merge conflicts in the GUI before check-in."],"tags":["merge","external-library","version-control","validation"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}