{"record":{"id":"bcbe255fd1d14648","repo":"CloakHQ/CloakBrowser","slug":"geoip-lookup-failed-for-ip-detail","errorCode":null,"errorMessage":"GeoIP lookup failed for ${ip}: ${detail}","messagePattern":"GeoIP lookup failed for (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"js/src/geoip.ts","lineNumber":132,"sourceCode":"    throw new Error(\"GeoIP resolution failed: could not discover the egress IP\");\n  }\n\n  if (!dbPath) {\n    throw new Error(\"GeoIP resolution failed: GeoIP database is unavailable\");\n  }\n\n  try {\n    const buf = fs.readFileSync(dbPath);\n    const reader = new Reader(buf);\n    const result = reader.get(ip) as any;\n    const timezone: string | null = result?.location?.time_zone ?? null;\n    const countryCode: string | null = result?.country?.iso_code ?? null;\n    const locale =\n      countryCode ? (COUNTRY_LOCALE_MAP[countryCode] ?? null) : null;\n    return { timezone, locale, exitIp: ip };\n  } catch (error) {\n    const detail = error instanceof Error ? error.message : String(error);\n    throw new Error(`GeoIP lookup failed for ${ip}: ${detail}`, { cause: error });\n  }\n}\n\nfunction getGeoipTimeoutMs(): number {\n  const raw = process.env.CLOAKBROWSER_GEOIP_TIMEOUT_SECONDS;\n  if (!raw) return DEFAULT_GEOIP_TIMEOUT_MS;\n  const timeoutSeconds = Number(raw);\n  if (!Number.isFinite(timeoutSeconds)) {\n    console.warn(`[cloakbrowser] Invalid CLOAKBROWSER_GEOIP_TIMEOUT_SECONDS=${raw}; using ${DEFAULT_GEOIP_TIMEOUT_MS / 1000}s`);\n    return DEFAULT_GEOIP_TIMEOUT_MS;\n  }\n  return Math.max(timeoutSeconds, 0) * 1000;\n}\n\nfunction deadlineFromTimeout(timeoutMs: number): number | null {\n  return timeoutMs > 0 ? performance.now() + timeoutMs : null;\n}\n","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/CloakHQ/CloakBrowser/blob/d6bad5de261bedf025280ace1d14e800aee13923/js/src/geoip.ts#L114-L150","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst dbPath = '/tmp/geo.mmdb'; // possibly corrupt\n\n// after\nconst dbPath = await downloadGeoipDb(dest).catch(async () => {\n  await fs.promises.rm(dest, { force: true });\n  throw new Error('GeoIP DB download failed; remove and retry');\n});","handlingStrategy":"try-catch","validationCode":"import fs from 'node:fs';\nfunction looksLikeMmdb(path: string): boolean {\n  const fd = fs.openSync(path, 'r');\n  const buf = Buffer.alloc(14);\n  fs.readSync(fd, buf, 0, 14, 0); fs.closeSync(fd);\n  return buf.toString('ascii', 12, 14) === '~~'; // mmdb metadata marker start\n}","typeGuard":"function isGeoipLookupError(e: unknown): e is Error {\n  return e instanceof Error && e.message.startsWith('GeoIP lookup failed for');\n}","tryCatchPattern":"try { geo = await resolveProxyGeo({ ip, dbPath }); }\ncatch (e) {\n  if (isGeoipLookupError(e)) {\n    await fs.promises.rm(dbPath, { force: true });\n    await downloadGeoipDb(dbPath);\n    geo = await resolveProxyGeo({ ip, dbPath }); // retry with fresh DB\n  } else throw e;\n}","preventionTips":["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"],"tags":["geoip","maxmind","corrupt-file","data-integrity"],"backgroundTag":"geoip-lookup-corrupt-database","analyzedSha":"d6bad5de261bedf025280ace1d14e800aee13923","analyzedAt":"2026-08-28T14:13:12.918Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}