CloakHQ/CloakBrowser · error · Error

GeoIP resolution failed: could not discover the egress IP

Error message

GeoIP resolution failed: could not discover the egress IP

What it means

resolveProxyGeo could not determine the egress IP: neither echo services nor proxy hostname resolution returned an IP before the deadline. The library throws it because all subsequent GeoIP lookups require a concrete egress IP to map to a country/timezone.

Source

Thrown at js/src/geoip.ts:114

  // timeout (a first-use ~70MB fetch legitimately outlasts it).
  const dbPath = await ensureGeoipDb();

  const timeoutMs = getGeoipTimeoutMs();
  const deadline = deadlineFromTimeout(timeoutMs);

  // Exit IP (through proxy, or the machine's own public IP when proxyUrl is
  // falsy) is most accurate — gateway DNS may differ from exit. Resolved even
  // when the DB is unavailable: the IP does not need the DB, and dropping it on
  // a DB hiccup would let WebRTC fall back to the real IP behind a proxy while
  // the connection shows the proxy IP — a real deanonymization.
  let ip = await resolveExitIp(proxyUrl, remainingMs(deadline));
  // Hostname fallback only applies to a proxy; no proxy → echo services only
  if (!ip && proxyUrl && !deadlineExpired(deadline)) ip = await resolveProxyIp(proxyUrl);
  if (!ip || deadlineExpired(deadline)) {
    if (deadlineExpired(deadline)) {
      throw new Error(`GeoIP resolution timed out after ${timeoutMs / 1000}s`);
    }
    throw new Error("GeoIP resolution failed: could not discover the egress IP");
  }

  if (!dbPath) {
    throw new Error("GeoIP resolution failed: GeoIP database is unavailable");
  }

  try {
    const buf = fs.readFileSync(dbPath);
    const reader = new Reader(buf);
    const result = reader.get(ip) as any;
    const timezone: string | null = result?.location?.time_zone ?? null;
    const countryCode: string | null = result?.country?.iso_code ?? null;
    const locale =
      countryCode ? (COUNTRY_LOCALE_MAP[countryCode] ?? null) : null;
    return { timezone, locale, exitIp: ip };
  } catch (error) {
    const detail = error instanceof Error ? error.message : String(error);
    throw new Error(`GeoIP lookup failed for ${ip}: ${detail}`, { cause: error });

View on GitHub (pinned to d6bad5de26)

Solutions

  1. Check network egress and DNS: curl an echo service (e.g. ifconfig.me) from the same host/container
  2. Verify the proxy URL is reachable and its hostname resolves; test with curl -x <proxyUrl> https://ifconfig.me
  3. Increase CLOAKBROWSER_GEOIP_TIMEOUT_SECONDS so proxy hostname resolution fits in the deadline
  4. Skip GeoIP resolution and pass timezone/locale explicitly if you already know them

Example fix

// before
const geo = await resolveProxyGeo({ proxyUrl, dbPath });

// after
const geo = await resolveProxyGeo({
  proxyUrl,
  dbPath,
  timeoutMs: 30_000,
}).catch((err) => {
  if (err.message.includes('egress IP')) {
    return { timezone: 'UTC', locale: 'en-US', exitIp: null };
  }
  throw err;
});
Defensive patterns

Strategy: fallback

Validate before calling

async function canReachEgress(proxyUrl?: string): Promise<boolean> {
  try {
    const url = 'https://ifconfig.me';
    const res = await fetch(url, proxyUrl ? { agent: new ProxyAgent(proxyUrl) } : {});
    return res.ok;
  } catch { return false; }
}

Type guard

function isEgressDiscoveryError(e: unknown): e is Error {
  return e instanceof Error && e.message.includes('could not discover the egress IP');
}

Try / catch

try {
  geo = await resolveProxyGeo({ proxyUrl, dbPath });
} catch (e) {
  if (isEgressDiscoveryError(e)) geo = { timezone: 'UTC', locale: 'en-US', exitIp: null };
  else throw e;
}

Prevention

When it happens

Trigger: Calling resolveProxyGeo (directly or via maybeResolveGeoip) with no reachable echo service, a proxyUrl whose hostname fails DNS resolution, or a deadline that expired mid-discovery (env CLOAKBROWSER_GEOIP_TIMEOUT_SECONDS too small).

Common situations: Offline/sandboxed environments blocking echo endpoints, an unreachable or misconfigured proxy (typo'd host, dead upstream), DNS failures inside containers, or aggressive timeouts on slow proxy connections.

Related errors


AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28). Data as JSON: /api/errors/f942db9bbea8ec7a. Report an issue: GitHub.