NationalSecurityAgency/ghidra · error · InvalidInputException
Didn't remove external library {libName}
Error message
Didn't remove external library {libName} What it means
Thrown as an InvalidInputException by removeExternalLibrary when ExternalManager.removeExternalLibrary(libName) returns false, meaning the external library could not be removed from the program even though it appeared to exist and was empty. The companion earlier check already guards the 'not empty' case, so this throw specifically signals the removal API itself failed (the library was absent or the model rejected the mutation). Callers are expected to treat it as a hard failure of the merge step rather than a transient condition.
Source
Thrown at Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalProgramMerger.java:585
}
/**
* Removes the indicated external library from the indicated program version
* if it is empty.
* @param program the program
* @param libName the external library name
* @throws InvalidInputException if there is no such enterrnal library in the program
*/
private void removeExternalLibrary(Program program, String libName)
throws InvalidInputException {
ExternalManager extMgr = program.getExternalManager();
ExternalLocationIterator iter = extMgr.getExternalLocations(libName);
if (iter.hasNext()) {
throw new InvalidInputException(
"Didn't remove external library " + libName + " since it isn't empty.");
}
if (!extMgr.removeExternalLibrary(libName)) {
throw new InvalidInputException("Didn't remove external library " + libName);
}
}
/**
* Determines whether the latest external program name and my external program name are equals.
* @param latestName the latest external program name or null.
* @param myName my external program name or null.
* @return true if the names are equal.
*/
private boolean same(String latestName, String myName) {
return SystemUtilities.isEqual(latestName, myName);
}
/**
* Performs a manual merge of external program conflicts.
* @param chosenConflictOption ASK_USER means interactively resolve conflicts.
* JUnit testing also allows setting this to LATEST, MY, or ORIGINAL to force
* selection of a particular version change.View on GitHub (pinned to d5f144c24d)
Solutions
- Re-check extMgr.hasExternalLibrary(libName) immediately before calling removeExternalLibrary, and skip removal if it is already gone.
- Ensure the result program is checked out / writable and that no other thread is mutating the ExternalManager during the merge.
- Wrap the call in try/catch(InvalidInputException) and log + continue if removal is non-fatal to your merge pass.
- If the library is genuinely empty but removal fails, inspect the program's external locations for stale/dangling entries blocking the delete.
Example fix
// before
private void removeExternalLibrary(Program program, String libName) throws InvalidInputException {
ExternalManager extMgr = program.getExternalManager();
if (extMgr.getExternalLocations(libName).hasNext()) {
throw new InvalidInputException("Didn't remove external library " + libName + " since it isn't empty.");
}
if (!extMgr.removeExternalLibrary(libName)) {
throw new InvalidInputException("Didn't remove external library " + libName);
}
}
// after — guard the already-removed case
private void removeExternalLibrary(Program program, String libName) throws InvalidInputException {
ExternalManager extMgr = program.getExternalManager();
if (!extMgr.hasExternalLibrary(libName)) {
return; // already gone, nothing to do
}
if (extMgr.getExternalLocations(libName).hasNext()) {
throw new InvalidInputException("Didn't remove external library " + libName + " since it isn't empty.");
}
if (!extMgr.removeExternalLibrary(libName)) {
throw new InvalidInputException("Didn't remove external library " + libName);
}
} Defensive patterns
Strategy: validation
Validate before calling
ExternalManager extMgr = program.getExternalManager();
if (!extMgr.hasExternalLibrary(libName)) {
return; // nothing to remove
}
if (extMgr.getExternalLocations(libName).hasNext()) {
// library not empty — do not call remove
return;
} Type guard
boolean removable = program.getExternalManager().hasExternalLibrary(libName)
&& !program.getExternalManager().getExternalLocations(libName).hasNext(); Try / catch
try {
removeExternalLibrary(program, libName);
} catch (InvalidInputException e) {
Msg.warn(this, "Skipping external library removal: " + e.getMessage());
} Prevention
- Check hasExternalLibrary and emptiness before removeExternalLibrary.
- Run the merge with the result program writable and no concurrent mutations.
- Make removal idempotent — tolerate the already-removed case.
When it happens
Trigger: Calling removeExternalLibrary(program, libName) where extMgr.getExternalLocations(libName).hasNext() is false (empty) but extMgr.removeExternalLibrary(libName) still returns false — e.g. the library name was removed by a concurrent transaction, the name does not actually exist in the ExternalManager, or the underlying program is read-only/immutable during the merge.
Common situations: Version-control merge of two Ghidra program checkouts where both sides deleted or renamed the same external library; running the listing/externals merge on a program opened read-only; an earlier merge phase already removed the library so a second pass finds nothing to remove.
Related errors
- Couldn't get namespace '" + newSymbol.getParentNamespace().t
- Didn't remove external library {libName} since it isn't empt
- The specified source address never had an external address p
- An external address translator can only handle a single addr
- The specified source address set never had an external addre
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/77645908551eed1f.
Report an issue: GitHub.