{"record":{"id":"6dba29f15ca25c1b","repo":"moeru-ai/airi","slug":"weather-request-failed-res-status","errorCode":null,"errorMessage":"Weather request failed: ${res.status}","messagePattern":"Weather request failed: (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/stage-tamagotchi/src/renderer/stores/tools/builtin/weather-api.ts","lineNumber":125,"sourceCode":"  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',\n    forecast_days: '1',\n  })\n\n  const res = await fetch(`https://api.open-meteo.com/v1/forecast?${params}`)\n\n  if (!res.ok)\n    throw new Error(`Weather request failed: ${res.status}`)\n\n  const data: OpenMeteoWeather = await res.json()\n  const current = data.current\n  const isNight = current.is_day === 0\n  const { conditionCode, condition } = mapWmoCode(current.weather_code, isNight)\n\n  return {\n    city: geo.name,\n    country: geo.country,\n    temperature: `${Math.round(current.temperature_2m)}°C`,\n    condition,\n    conditionCode,\n    isNight,\n    feelsLike: `${Math.round(current.apparent_temperature)}°C`,\n    humidity: `${current.relative_humidity_2m}%`,\n    wind: `${Math.round(current.wind_speed_10m)} km/h`,\n    precipitation: `${current.precipitation} mm`,\n    high: data.daily ? `${Math.round(data.daily.temperature_2m_max[0])}°C` : undefined,","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/apps/stage-tamagotchi/src/renderer/stores/tools/builtin/weather-api.ts#L107-L143","documentation":"Thrown by fetchWeather when the Open-Meteo forecast endpoint responds non-ok after geocoding already succeeded. The status code is embedded. Coordinates were valid (geocode worked), but the forecast query failed.","triggerScenarios":"Open-Meteo forecast API returned 4xx/5xx — rate limited (429), service incident (5xx), malformed query params (e.g. unsupported variable name), or proxy error. Distinct from [56] which is the geocoding step.","commonSituations":"Transient outage of the forecast endpoint specifically; rate limiting after many weather calls; URLSearchParams included an unsupported field; network blip between geocode and forecast.","solutions":["Retry the forecast call — 5xx/429 are transient.","Verify the URLSearchParams current/daily field names match the current Open-Meteo schema.","Check the Open-Meteo status page.","Cache geocode results so a forecast retry doesn't re-pay geocoding."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function fetchWeatherWithRetry(city: string, attempts = 2) {\n  for (let i = 0; i < attempts; i++) {\n    try { return await fetchWeather(city) }\n    catch (e) {\n      const msg = e instanceof Error ? e.message : ''\n      if (msg.startsWith('Weather request failed') && i < attempts - 1) {\n        await new Promise(r => setTimeout(r, 800)); continue\n      }\n      throw e\n    }\n  }\n  throw new Error('unreachable')\n}","preventionTips":["Cache geocode results so forecast retries don't re-run geocoding.","Verify URLSearchParams field names against the current Open-Meteo schema.","Retry with backoff on 429/5xx."],"tags":["weather","network","upstream","rate-limit","forecast"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}