{"record":{"id":"41e960f935105415","repo":"moeru-ai/airi","slug":"geocoding-request-failed-res-status","errorCode":null,"errorMessage":"Geocoding request failed: ${res.status}","messagePattern":"Geocoding request failed: (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/stage-tamagotchi/src/renderer/stores/tools/builtin/weather-api.ts","lineNumber":100,"sourceCode":"    const nightVariants: Record<string, string> = {\n      'clear-day': 'clear-night',\n      'partly-cloudy-day': 'partly-cloudy-night',\n    }\n    return {\n      ...mapped,\n      conditionCode: nightVariants[mapped.conditionCode] ?? mapped.conditionCode,\n    }\n  }\n\n  return mapped\n}\n\nexport async function geocodeCity(city: string): Promise<{ name: string, latitude: number, longitude: number, country: string }> {\n  const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1&language=en&format=json`\n  const res = await fetch(url)\n\n  if (!res.ok)\n    throw new Error(`Geocoding request failed: ${res.status}`)\n\n  const data: GeocodingResult = await res.json()\n\n  if (!data.results?.length)\n    throw new Error(`City not found: \"${city}\"`)\n\n  const result = data.results[0]\n  return { name: result.name, latitude: result.latitude, longitude: result.longitude, country: result.country }\n}\n\nexport async function fetchWeather(city: string): Promise<WeatherData> {\n  const geo = await geocodeCity(city)\n\n  const params = new URLSearchParams({\n    latitude: String(geo.latitude),\n    longitude: String(geo.longitude),\n    current: 'temperature_2m,relative_humidity_2m,apparent_temperature,weather_code,wind_speed_10m,precipitation,is_day',\n    daily: 'temperature_2m_max,temperature_2m_min',","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/apps/stage-tamagotchi/src/renderer/stores/tools/builtin/weather-api.ts#L82-L118","documentation":"Thrown by geocodeCity when the Open-Meteo geocoding API responds with a non-ok HTTP status (res.ok is false). The URL is built from the user-supplied city via encodeURIComponent. The status code is embedded in the message for diagnostics.","triggerScenarios":"Open-Meteo geocoding endpoint returned 4xx/5xx — malformed city parameter after encoding, rate limited (429), service down (5xx), or network proxy returned an error status.","commonSituations":"Transient Open-Meteo outage; aggressive polling hit rate limits; very long/special-character city string; corporate proxy returning 403/502.","solutions":["Retry after a short delay — 5xx and 429 are typically transient.","Sanitize/trim the city input before encoding.","Check Open-Meteo status page for incidents.","If behind a proxy, verify it permits geocoding-api.open-meteo.com."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"function isLikelyValidCity(city: string): boolean {\n  return typeof city === 'string' && city.trim().length > 0 && city.trim().length <= 100\n}","typeGuard":null,"tryCatchPattern":"async function geocodeWithRetry(city: string, attempts = 2) {\n  for (let i = 0; i < attempts; i++) {\n    try { return await geocodeCity(city) }\n    catch (e) {\n      if (i === attempts - 1) throw e\n      await new Promise(r => setTimeout(r, 800))\n    }\n  }\n  throw new Error('unreachable')\n}","preventionTips":["Trim and sanity-check the city string before encoding.","Retry on 429/5xx with backoff.","Cache successful geocode results to reduce API load."],"tags":["weather","network","geocoding","upstream","rate-limit"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}