TechnitiumSoftware/DnsServer · error · InvalidDataException
External to internal translation entries must have same…
Error message
External to internal translation entries must have same prefix length: {strExternal} - {strInternal} What it means
SplitHorizonApp's external-to-internal translation additionally requires both endpoints to share the same prefix length (e.g. /24 to /24, /32 to /32). This InvalidDataException fires when the external and internal NetworkAddress values have matching families but different PrefixLength values, since asymmetric prefixes would translate the wrong number of addresses.
Solutions
- Match the prefix length on both sides of each translation entry.
- For single-host translation use /32 (IPv4) or /128 (IPv6) on both external and internal.
- If pool sizes genuinely differ, split into multiple equal-prefix entries instead.
Example fix
// before
"externalToInternalTranslation": {
"203.0.113.0/29": "10.0.0.1/32"
}
// after
"externalToInternalTranslation": {
"203.0.113.0/29": "10.0.0.0/29"
} Defensive patterns
Strategy: validation
Validate before calling
static void AssertSamePrefixLength(string ext, string intl)
{
var ep = int.Parse(ext.Split('/')[1]);
var ip = int.Parse(intl.Split('/')[1]);
if (ep != ip)
throw new InvalidDataException($"Prefix length mismatch: {ext} - {intl}");
}
foreach (var (ext, intl) in translationEntries)
AssertSamePrefixLength(ext, intl); Try / catch
try { /* load translation config */ }
catch (InvalidDataException ex) when (ex.Message.Contains("same prefix length"))
{ /* report the entry and abort config apply */ } Prevention
- Mirror prefix lengths on both sides of every translation entry.
- Use /32 and /128 for single-host NAT on both endpoints.
- Document that 1:1 translation requires equal-size pools.
When it happens
Trigger: A translation entry where the external CIDR and internal CIDR differ in mask size, e.g. external '203.0.113.0/24' (256 addresses) mapped to internal '10.0.0.1/32' (single host).
Common situations: Configuring a /29 external block to a /24 internal subnet (or vice versa) thinking the translation auto-scales; forgetting that 1:1 NAT needs equal-size pools.
Related errors
- External to internal translation entries must have same…
- Network group map contains an invalid network address
- At least one primary name server address must be specified…
- Invalid domain name [ ]: IP address cannot be used for DNS…
- MaxStatFileDays must be greater than or equal to 0.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/3e5889131742a7a0.
Report an issue: GitHub.
Appendix: source
Thrown at Apps/SplitHorizonApp/AddressTranslation.cs:389
JsonElement jsonExternalToInternalTranslation = jsonGroup.GetProperty("externalToInternalTranslation");
Dictionary<IPAddress, IPAddress> externalToInternalIpTranslation = new Dictionary<IPAddress, IPAddress>();
Dictionary<IPAddress, IPAddress> internalToExternalIpTranslation = new Dictionary<IPAddress, IPAddress>();
List<KeyValuePair<NetworkAddress, NetworkAddress>> externalToInternalNetworkTranslation = new List<KeyValuePair<NetworkAddress, NetworkAddress>>();
foreach (JsonProperty jsonProperty in jsonExternalToInternalTranslation.EnumerateObject())
{
string strExternal = jsonProperty.Name;
string strInternal = jsonProperty.Value.GetString();
NetworkAddress external = NetworkAddress.Parse(strExternal);
NetworkAddress @internal = NetworkAddress.Parse(strInternal);
if (external.AddressFamily != @internal.AddressFamily)
throw new InvalidDataException("External to internal translation entries must have same address family: " + strExternal + " - " + strInternal);
if (external.PrefixLength != @internal.PrefixLength)
throw new InvalidDataException("External to internal translation entries must have same prefix length: " + strExternal + " - " + strInternal);
if (
((external.AddressFamily == AddressFamily.InterNetwork) && (external.PrefixLength == 32)) ||
((external.AddressFamily == AddressFamily.InterNetworkV6) && (external.PrefixLength == 128))
)
{
externalToInternalIpTranslation.TryAdd(external.Address, @internal.Address);
if (_translateReverseLookups)
internalToExternalIpTranslation.TryAdd(@internal.Address, external.Address);
}
else
{
externalToInternalNetworkTranslation.Add(new KeyValuePair<NetworkAddress, NetworkAddress>(external, @internal));
}
}
_externalToInternalTranslation = externalToInternalIpTranslation;View on GitHub (pinned to d0484b6c1e)