CloakHQ/CloakBrowser · error · Error
GeoIP resolution failed: could not determine ${missing.join(
Error message
GeoIP resolution failed: could not determine ${missing.join(" and ")} What it means
maybeResolveGeoip finished but could not determine one or both of timezone and locale: neither the caller-supplied values nor the GeoIP result produced them. The message names exactly which fields are missing.
Source
Thrown at js/src/geoip.ts:484
// When both tz/locale are explicit, resolve the exit IP for WebRTC — but only
// with a proxy. With no proxy the WebRTC IP would just be the real connection
// IP the site already sees (a no-op), so skip the third-party echo call.
if (timezone && locale) {
if (!proxyUrl) return { timezone, locale };
const timeoutMs = getGeoipTimeoutMs();
const exitIp = await resolveExitIp(proxyUrl, timeoutMs) ?? undefined;
return { timezone, locale, exitIp };
}
const { timezone: geoTz, locale: geoLocale, exitIp: geoExitIp } = await resolveProxyGeo(proxyUrl);
const resolvedTimezone = timezone ?? geoTz ?? undefined;
const resolvedLocale = locale ?? geoLocale ?? undefined;
const missing = [
resolvedTimezone ? null : "timezone",
resolvedLocale ? null : "locale",
].filter((value): value is string => value !== null);
if (missing.length > 0) {
throw new Error(`GeoIP resolution failed: could not determine ${missing.join(" and ")}`);
}
return {
timezone: resolvedTimezone,
locale: resolvedLocale,
exitIp: geoExitIp ?? undefined,
};
}
/**
* Append `--fingerprint-webrtc-ip=<exitIp>` unless the user already set the flag.
* The exit IP comes free from the geoip lookup; it spoofs the WebRTC IP to the
* egress IP. No-op when there is no exit IP or the flag is already present. This
* rule must stay identical across every launch path, so it lives in one place.
*/
export function appendWebrtcExitIp(
args: string[] | undefined,
exitIp: string | undefined,
): string[] | undefined {View on GitHub (pinned to d6bad5de26)
Solutions
- Pass explicit timezone and locale when you know them (they take precedence and bypass the error)
- Update or extend COUNTRY_LOCALE_MAP / use a newer GeoIP database covering the exit IP
- If locale cannot be inferred, default it (e.g. 'en-US') instead of failing
Example fix
// before
const { timezone, locale } = await maybeResolveGeoip({ ip, dbPath });
// after
const { timezone, locale } = await maybeResolveGeoip({
ip,
dbPath,
timezone: 'America/New_York', // known ahead of time
locale: 'en-US',
}); Defensive patterns
Strategy: fallback
Validate before calling
const desired = { timezone: 'America/New_York', locale: 'en-US' };
const needGeoip = !desired.timezone || !desired.locale;
if (!needGeoip) { /* skip maybeResolveGeoip entirely */ } Type guard
function missingGeoFields(e: unknown): string[] | null {
if (!(e instanceof Error)) return null;
const m = e.message.match(/could not determine (.+)$/);
return m ? m[1].split(' and ') : null;
} Try / catch
try { return await maybeResolveGeoip(opts); }
catch (e) {
const missing = missingGeoFields(e);
if (missing) {
return { timezone: opts.timezone ?? 'UTC', locale: opts.locale ?? 'en-US', exitIp: undefined };
}
throw e;
} Prevention
- Pass known timezone/locale explicitly whenever available
- Default locale before calling so only genuinely unknown fields rely on GeoIP
- Treat GeoIP as best-effort: catch and degrade rather than fail the session
When it happens
Trigger: Calling maybeResolveGeoip without timezone/locale while the GeoIP lookup returned a country with no entry in COUNTRY_LOCALE_MAP (locale missing), or the reader result lacked a timezone field; also when GeoIP was skipped and no explicit values were given.
Common situations: Exotic IPs (satellite/VPN providers) with sparse MaxMind data, countries not covered by the locale map, or callers assuming GeoIP always succeeds and omitting explicit timezone/locale options.
Related errors
- GeoIP resolution failed: could not determine {missing joined
- GeoIP resolution failed: could not discover the egress IP
- GeoIP resolution failed: GeoIP database is unavailable
- GeoIP lookup failed for ${ip}: ${detail}
- HTTP ${response.status}
AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28).
Data as JSON: /api/errors/6b35adaafd879062.
Report an issue: GitHub.