{"record":{"id":"ddabe3e18f909401","repo":"NationalSecurityAgency/ghidra","slug":"the-specified-source-address-never-had-an-external","errorCode":null,"errorMessage":"The specified source address never had an external address pair added to the translator.","messagePattern":"The specified source address never had an external address pair added to the translator\\.","errorType":"exception","errorClass":"AddressTranslationException","httpStatus":null,"severity":"error","filePath":"Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalsAddressTranslator.java","lineNumber":70,"sourceCode":"\t}\n\n\tpublic void setPair(Address destinationAddress, Address sourceAddress) {\n\t\t// Should this actually do a clear first, instead of the check and possible remove?\n\t\tif (destinationAddress != null) {\n\t\t\taddressMap.put(sourceAddress, destinationAddress);\n\t\t}\n\t\telse {\n\t\t\taddressMap.remove(sourceAddress);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Address getAddress(Address sourceAddress) {\n\t\tAddress destinationAddress = addressMap.get(sourceAddress);\n\t\tif (destinationAddress != null) {\n\t\t\treturn destinationAddress;\n\t\t}\n\t\tthrow new AddressTranslationException(\n\t\t\t\"The specified source address never had an external address pair added to the translator.\");\n\t}\n\n\t@Override\n\tpublic boolean isOneForOneTranslator() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic AddressSet getAddressSet(AddressSetView sourceAddressSet) {\n\t\tif (sourceAddressSet == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (sourceAddressSet.getNumAddresses() > 1) {\n\t\t\tthrow new AddressTranslationException(\n\t\t\t\t\"An external address translator can only handle a single address at a time, if that.\");\n\t\t}\n\t\tAddressSet destinationSet = new AddressSet();","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalsAddressTranslator.java#L52-L88","documentation":"Thrown as AddressTranslationException by ExternalsAddressTranslator.getAddress when the supplied source address has no entry in the translator's internal addressMap. The class is explicitly one-to-one and requires every translatable source address to be registered first via setPair(destination, source). A lookup miss means the caller forgot (or failed) to register the pair before querying.","triggerScenarios":"Calling getAddress(sourceAddress) on an ExternalsAddressTranslator instance without first calling setPair(destination, source) for that exact source address; passing a source address from a different program or address space than the one used at registration time.","commonSituations":"Merging external functions/labels across two programs where the caller pre-populated pairs for some external locations but not all; refactoring a ProgramMerge flow and dropping the setPair loop; using a source address computed via a different DiffUtility path than the one used to build the map.","solutions":["Before calling getAddress, ensure setPair(destination, source) has been invoked for every external source address you intend to translate.","Prefer the higher-level ProgramMerge helpers that build the translator pairs for you rather than calling getAddress directly.","Wrap the call in try/catch(AddressTranslationException) and fall back to SimpleDiffUtility.getCompatibleAddress for unmapped externals.","If you iterate a set of source addresses, register the full set up front rather than ad hoc."],"exampleFix":"// before\nAddress dest = translator.getAddress(sourceAddr); // throws if not registered\n\n// after — register first, or fall back\ntranslator.setPair(mappedDest, sourceAddr);\nAddress dest = translator.getAddress(sourceAddr);","handlingStrategy":"validation","validationCode":"// register the pair before lookup\ntranslator.setPair(destinationAddress, sourceAddress);\n// optionally probe without throwing\nboolean known = /* expose addressMap.containsKey via a wrapper */;","typeGuard":"// no direct key check on the interface; guard by ensuring setPair was called\nassert translator.getAddress(dest) != null : \"pair not registered\";","tryCatchPattern":"try {\n    Address d = translator.getAddress(source);\n} catch (AddressTranslationException e) {\n    d = SimpleDiffUtility.getCompatibleAddress(srcProgram, source, destProgram);\n}","preventionTips":["Always call setPair(destination, source) for every external location up front.","Prefer ProgramMerge's built-in translator setup over manual getAddress calls.","Keep a single source of truth for which external addresses are registered."],"tags":["ghidra","merge","address-translator","external"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}