CloakHQ/CloakBrowser · error · Error
GeoIP lookup failed for ${ip}: ${detail}
Error message
GeoIP lookup failed for ${ip}: ${detail} What it means
The MaxMind Reader threw while looking up the discovered egress IP; the thrown error wraps the underlying message as `GeoIP lookup failed for <ip>: <detail>`. This is a lower-level failure inside maxmind Reader.get(), not a discovery problem.
Source
Thrown at js/src/geoip.ts:132
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 });
}
}
function getGeoipTimeoutMs(): number {
const raw = process.env.CLOAKBROWSER_GEOIP_TIMEOUT_SECONDS;
if (!raw) return DEFAULT_GEOIP_TIMEOUT_MS;
const timeoutSeconds = Number(raw);
if (!Number.isFinite(timeoutSeconds)) {
console.warn(`[cloakbrowser] Invalid CLOAKBROWSER_GEOIP_TIMEOUT_SECONDS=${raw}; using ${DEFAULT_GEOIP_TIMEOUT_MS / 1000}s`);
return DEFAULT_GEOIP_TIMEOUT_MS;
}
return Math.max(timeoutSeconds, 0) * 1000;
}
function deadlineFromTimeout(timeoutMs: number): number | null {
return timeoutMs > 0 ? performance.now() + timeoutMs : null;
}
View on GitHub (pinned to d6bad5de26)
Solutions
- Re-download the GeoIP database (delete the stale file and rerun downloadGeoipDb) to fix corruption
- Verify the dbPath file is a valid binary mmdb (check size/magic bytes), not an HTML error page
- Ensure the ip value is a plain IPv4/IPv6 string (no port, scheme, or whitespace)
- Upgrade the maxmind package to match the database edition
Example fix
// before
const dbPath = '/tmp/geo.mmdb'; // possibly corrupt
// after
const dbPath = await downloadGeoipDb(dest).catch(async () => {
await fs.promises.rm(dest, { force: true });
throw new Error('GeoIP DB download failed; remove and retry');
}); Defensive patterns
Strategy: try-catch
Validate before calling
import fs from 'node:fs';
function looksLikeMmdb(path: string): boolean {
const fd = fs.openSync(path, 'r');
const buf = Buffer.alloc(14);
fs.readSync(fd, buf, 0, 14, 0); fs.closeSync(fd);
return buf.toString('ascii', 12, 14) === '~~'; // mmdb metadata marker start
} Type guard
function isGeoipLookupError(e: unknown): e is Error {
return e instanceof Error && e.message.startsWith('GeoIP lookup failed for');
} Try / catch
try { geo = await resolveProxyGeo({ ip, dbPath }); }
catch (e) {
if (isGeoipLookupError(e)) {
await fs.promises.rm(dbPath, { force: true });
await downloadGeoipDb(dbPath);
geo = await resolveProxyGeo({ ip, dbPath }); // retry with fresh DB
} else throw e;
} Prevention
- Validate the mmdb magic bytes/size after every download
- Re-download on a schedule to avoid long-lived corrupt files
- Sanitize ip strings (strip port/whitespace) before passing
When it happens
Trigger: Corrupt or truncated .mmdb file (partial download), a file that exists but is not a valid MaxMind DB, or a malformed/non-IP string passed as ip to resolveProxyGeo.
Common situations: Interrupted downloads leaving a broken .tmp/.mmdb file, wrong file passed as dbPath (e.g. an HTML error page), or version skew between the maxmind reader and the database format.
Related errors
- GeoIP resolution failed: GeoIP database is unavailable
- GeoIP resolution failed: GeoIP database is unavailable
- GeoIP lookup failed for {ip}: {exc.Message}
- GeoIP resolution failed: could not discover the egress IP
- HTTP ${response.status}
AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28).
Data as JSON: /api/errors/bcbe255fd1d14648.
Report an issue: GitHub.