santifer/career-ops · error · Error
plugin egress: ${hostname} resolved to no addresses
Error message
plugin egress: ${hostname} resolved to no addresses What it means
Thrown by `resolveAndValidate` (plugins/_net.mjs:97) when `dnsLookup` resolves successfully but returns an empty address array. This is a defensive guard: a well-formed resolver response with zero A/AAAA records is treated as a failure rather than silently producing an empty validated list (which would then connect nowhere or to a default). It is distinct from a DNS error (105) and from a blocked address (107).
Source
Thrown at plugins/_net.mjs:97
if (isBlockedIp(hostname)) {
if (allowsLocalhost && isLoopbackLiteral(hostname)) return [hostname];
throw new Error(`plugin egress to ${hostname} is blocked (private/loopback/metadata range)`);
}
return [hostname];
}
if (allowsLocalhost && LOOPBACK_HOSTS.has(hostname.toLowerCase())) {
// Local-AI providers (Ollama/LM Studio). Resolve but allow loopback through.
return ['127.0.0.1'];
}
let addrs;
try {
addrs = await dnsLookup(hostname, { all: true });
} catch (err) {
throw new Error(`plugin egress: cannot resolve ${hostname} — ${err.message}`);
}
if (!addrs.length) throw new Error(`plugin egress: ${hostname} resolved to no addresses`);
for (const { address } of addrs) {
if (isBlockedIp(address)) {
if (allowsLocalhost && isLoopbackLiteral(address)) continue;
throw new Error(`plugin egress: ${hostname} resolves to a blocked address (${address}) — possible SSRF/rebinding`);
}
}
return addrs.map(a => a.address);
}
function isLoopbackLiteral(ip) {
if (ip === '::1') return true;
if (isIP(ip) === 4) return ip.split('.')[0] === '127';
return false;
}
View on GitHub (pinned to 9b17a8ac97)
Solutions
- Confirm the hostname actually has A/AAAA records: `dig <hostname> A` and `dig <hostname> AAAA`.
- If the host is record-less by mistake, add an A record at the DNS provider, or use a hostname that has address records.
- If this is a fluke resolver response, retry; if it persists, switch resolver (`/etc/resolv.conf`) or check split-horizon config.
Defensive patterns
Strategy: validation
Validate before calling
import { lookup } from 'node:dns/promises';
import { Resolver } from 'node:dns';
// Confirm a hostname has A/AAAA records before relying on it.
async function assertHasAddressRecords(hostname) {
const addrs = await new Resolver().resolve4(hostname).catch(() => [])
.concat(await new Resolver().resolve6(hostname).catch(() => []));
if (!addrs.length) throw new Error(`'${hostname}' has no A/AAAA records — cannot be a fetch host.`);
}
await assertHasAddressRecords(hostname); Try / catch
try {
await resolveAndValidate(hostname);
} catch (err) {
if (/resolved to no addresses/.test(err.message)) {
console.error(`Config error: ${err.message} — use a host with address records.`);
} else throw err;
} Prevention
- Don't use mail-only or record-less hostnames as fetch targets.
- Validate A/AAAA existence in config linting.
When it happens
Trigger: The hostname exists in DNS but has no address records (e.g. only MX/TXT records, an apex with no A/AAAA), or a custom resolver returns `{ all: true }` with an empty list. The check `if (!addrs.length)` fires immediately after a successful lookup.
Common situations: A domain configured only for email (MX records, no A record) mistakenly used as a fetch host; a misbehaving split-horizon DNS returning empty internally; an IPv6-only hostname queried on an IPv4-only resolver; a temporary resolver glitch returning a valid-but-empty response.
Related errors
- plugin egress: cannot resolve ${hostname} — ${err.message}
- plugin egress: ${hostname} resolves to a blocked address (${
- plugin egress to ${hostname} is blocked (private/loopback/me
- DNS resolution returned no addresses for ${hostname}
- too many redirects (>${MAX_REDIRECTS}) for ${url}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/60e1c1c98669199a.
Report an issue: GitHub.