NationalSecurityAgency/ghidra · error · AddressTranslationException

An external address translator can only handle a single addr

Error message

An external address translator can only handle a single address at a time, if that.

What it means

Thrown as AddressTranslationException by ExternalsAddressTranslator.getAddressSet when the supplied AddressSetView contains more than one address. ExternalsAddressTranslator is declared one-for-one (isOneForOneTranslator() returns true) because external locations are individually mapped, so a multi-address set is unsupported by design.

Source

Thrown at Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalsAddressTranslator.java:85

		if (destinationAddress != null) {
			return destinationAddress;
		}
		throw new AddressTranslationException(
			"The specified source address never had an external address pair added to the translator.");
	}

	@Override
	public boolean isOneForOneTranslator() {
		return true;
	}

	@Override
	public AddressSet getAddressSet(AddressSetView sourceAddressSet) {
		if (sourceAddressSet == null) {
			return null;
		}
		if (sourceAddressSet.getNumAddresses() > 1) {
			throw new AddressTranslationException(
				"An external address translator can only handle a single address at a time, if that.");
		}
		AddressSet destinationSet = new AddressSet();
		if (sourceAddressSet.isEmpty()) {
			return destinationSet;
		}
		Address sourceAddress = sourceAddressSet.getMinAddress();
		Address destinationAddress = addressMap.get(sourceAddress);
		if (destinationAddress != null) {
			destinationSet.add(destinationAddress);
		}
		throw new AddressTranslationException(
			"The specified source address set never had an external address pair added to the translator.");
	}

	@Override
	public AddressRange getAddressRange(AddressRange sourceAddressRange)
			throws AddressTranslationException {

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Split the AddressSetView into single-address sets (or iterate Address by Address) before translation.
  2. Use a different AddressTranslator implementation that supports ranges for non-external spaces.
  3. Filter the set down to a single external location via intersection with the external address space.

Example fix

// before
AddressSet out = translator.getAddressSet(multiAddrSet); // throws

// after — translate one address at a time
AddressSet out = new AddressSet();
for (Address src : multiAddrSet.getAddresses(true)) {
    translator.setPair(mappedDest(src), src);
    out.add(translator.getAddress(src));
}
Defensive patterns

Strategy: validation

Validate before calling

if (sourceAddressSet == null || sourceAddressSet.getNumAddresses() > 1) {
    // translate address-by-address instead
    AddressSet out = new AddressSet();
    for (Address a : sourceAddressSet.getAddresses(true)) {
        translator.setPair(map(a), a);
        out.add(translator.getAddress(a));
    }
    return out;
}

Type guard

boolean safeForSet = sourceAddressSet != null && sourceAddressSet.getNumAddresses() <= 1;

Try / catch

try {
    return translator.getAddressSet(sourceAddressSet);
} catch (AddressTranslationException e) {
    // fall back to per-address translation
}

Prevention

When it happens

Trigger: Passing an AddressSetView with getNumAddresses() > 1 into getAddressSet — for example the result of a listing address set, a memory range set, or a diff address set that was not narrowed to a single external location.

Common situations: Feeding a whole-function or whole-block address set into a translator built only for external single addresses; reusing a generic ProgramMerge translator on external space without splitting it.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/9c68bb582f525906. Report an issue: GitHub.