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

  1. Verify the hostname with `dig +short hostname` or `nslookup hostname` from the same machine.
  2. Update the URL in portals.yml / pipeline.md to the current careers subdomain.
  3. If DNS works locally but fails in CI, check the CI resolver and /etc/resolv.conf.
  4. 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

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

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/3a3e54597bb8c766. Report an issue: GitHub.