CloakHQ/CloakBrowser · error · Error
GeoIP resolution failed: GeoIP database is unavailable
Error message
GeoIP resolution failed: GeoIP database is unavailable
What it means
An egress IP was discovered, but no MaxMind GeoIP database file path was supplied or found, so the lookup cannot proceed. The library throws because the offline Reader requires a local .mmdb file.
Source
Thrown at js/src/geoip.ts:118
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 });
}
}
function getGeoipTimeoutMs(): number {View on GitHub (pinned to d6bad5de26)
Solutions
- Run downloadGeoipDb(dest) at startup and persist the resulting .mmdb path
- Pass the resolved dbPath into resolveProxyGeo / maybeResolveGeoip options
- Cache the downloaded database in CI or bundle it in the image so dbPath always exists
- Fall back to explicit timezone/locale when the DB cannot be provisioned
Example fix
// before
const geo = await resolveProxyGeo({ ip }); // no dbPath
// after
const dbPath = await ensureGeoipDb(); // downloads once, caches path
const geo = await resolveProxyGeo({ ip, dbPath }); Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
function assertGeoipDb(dbPath?: string): string {
if (!dbPath || !fs.existsSync(dbPath) || fs.statSync(dbPath).size === 0) {
throw new Error('GeoIP DB missing — run downloadGeoipDb first');
}
return dbPath;
} Type guard
function hasGeoipDb(dbPath?: string | null): dbPath is string {
return typeof dbPath === 'string' && dbPath.length > 0;
} Try / catch
try { geo = await resolveProxyGeo({ ip, dbPath }); }
catch (e) {
if (e instanceof Error && e.message.includes('database is unavailable')) {
await downloadGeoipDb(dest); geo = await resolveProxyGeo({ ip, dbPath: dest });
} else throw e;
} Prevention
- Bootstrap downloadGeoipDb at service startup before any GeoIP-dependent call
- Cache the .mmdb path in config rather than passing undefined
- Add a CI step verifying the DB file exists and is non-empty
When it happens
Trigger: Calling resolveProxyGeo without dbPath (or with an empty path) when the GeoIP database has not been pre-downloaded, e.g. downloadGeoipDb was never run or its result was not wired into the call.
Common situations: Fresh installs that skipped the DB download step, CI pipelines that do not cache the .mmdb artifact, or a download that failed silently earlier leaving no file path.
Related errors
- GeoIP lookup failed for ${ip}: ${detail}
- 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/6941d66b5e5a3ee9.
Report an issue: GitHub.