santifer/career-ops · error · Error
DNS resolution returned no addresses for ${hostname}
Error message
DNS resolution returned no addresses for ${hostname} What it means
Thrown by resolveDnsCached() in liveness-browser.mjs when the host resolver returned successfully but with an empty address array — i.e. DNS gave no A/AAAA records for the hostname. The result (or this Error) is cached per-hostname so repeated checks fail fast without hammering DNS. This is a fail-closed network precondition before any HTTP attempt.
Source
Thrown at liveness-browser.mjs:183
const previous = hostResolver;
hostResolver = resolver ?? resolveViaDns;
dnsCache.clear();
return () => {
hostResolver = previous;
dnsCache.clear();
};
}
async function resolveDnsCached(hostname) {
if (dnsCache.has(hostname)) {
const cached = dnsCache.get(hostname);
if (cached instanceof Error) throw cached;
return cached;
}
try {
const addresses = await hostResolver(hostname);
if (addresses.length === 0) {
throw new Error(`DNS resolution returned no addresses for ${hostname}`);
}
dnsCache.set(hostname, addresses);
return addresses;
} catch (err) {
dnsCache.set(hostname, err);
throw err;
}
}
async function validateUrlSecurity(urlString) {
const url = new URL(urlString.endsWith('.') ? urlString.slice(0, -1) : urlString);
const hostname = url.hostname;
const host = normalizeHost(hostname);
const addresses = await resolveDnsCached(host);
for (const ip of addresses) {
const norm = normalizeHost(ip);
const mapped = extractMappedIPv4(norm);
const candidates = mapped ? [norm, mapped] : [norm];View on GitHub (pinned to 9b17a8ac97)
Solutions
- Verify the hostname with `dig +short hostname` or `nslookup hostname` from the same machine.
- Update the URL in portals.yml / pipeline.md to the current careers subdomain.
- If DNS works locally but fails in CI, check the CI resolver and /etc/resolv.conf.
- Confirm the hostname has an A or AAAA record, not just MX/NS/TXT.
Defensive patterns
Strategy: validation
Validate before calling
const { Resolver } = require('dns').promises;
const r = new Resolver();
const addrs = await r.resolve4(hostname).catch(() => []);
if (addrs.length === 0) {
// skip the liveness check rather than letting resolveDnsCached throw
return { result: 'uncertain', reason: 'no DNS records' };
} Try / catch
try {
await checkUrlLiveness(page, url);
} catch (e) {
if (e.message.startsWith('DNS resolution returned no addresses')) {
// hostname no longer resolves — flag the portal entry as stale
markPortalStale(url);
} else throw e;
} Prevention
- Keep portal URLs current — prune subdomains that companies have retired.
- When adding a portal, verify it resolves with `dig +short` first.
- Treat persistent DNS empties as stale-portal signals and surface them in a cleanup report.
- Don't conflate this with a network error — empty results mean the hostname has no records.
When it happens
Trigger: A hostname that resolves to zero records: a typo (jobs.example.co vs .com), a recently decommissioned subdomain, a domain with only CNAME/MX but no A/AAAA, or a resolver that returns an empty list on NXDOMAIN-like outcomes. hostResolver returns [] and addresses.length === 0 triggers the throw.
Common situations: Stale portal URL in portals.yml pointing at a removed subdomain; company migrated careers site and old hostname no longer resolves; transient DNS misconfiguration on the local resolver; a hostname that only has a CNAME chain the resolver flattened to nothing.
Understand the failure class
- DNS resolution errors: ENOTFOUND and getaddrinfo failures — how hostname lookups fail and how to debug them.
Related errors
- Access denied: Egress guard blocked private target IP ${ip}
- Invalid URL: ${url}
- plugin egress: ${hostname} resolves to a blocked address (${
- Refusing non-HTTP(S) URL: ${url}
- Refusing private/loopback host: ${host}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/3a3e54597bb8c766.
Report an issue: GitHub.