{"record":{"id":"3011fb871e957eef","repo":"moeru-ai/airi","slug":"city-not-found-city","errorCode":null,"errorMessage":"City not found: \"${city}\"","messagePattern":"City not found: \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/stage-tamagotchi/src/renderer/stores/tools/builtin/weather-api.ts","lineNumber":105,"sourceCode":"      ...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',\n    forecast_days: '1',\n  })\n\n  const res = await fetch(`https://api.open-meteo.com/v1/forecast?${params}`)\n","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/apps/stage-tamagotchi/src/renderer/stores/tools/builtin/weather-api.ts#L87-L123","documentation":"Thrown by geocodeCity when the geocoding request succeeded (res.ok) but data.results is empty or undefined — the API found no match for the city. This is a logical 'not found', not a transport error.","triggerScenarios":"User asked for weather in a city name Open-Meteo cannot resolve — typo, non-existent place, ambiguous name with count=1 returning nothing, or a city in a script/language the geocoder doesn't index.","commonSituations":"Typo in city name; very small/obscure locality not in the geocoder; user used a local-language name not indexed; city merged/renamed.","solutions":["Correct the city spelling or use the official English name.","Try a broader region name (e.g. the province or nearby major city).","Increase the geocoding count parameter and disambiguate, or accept country codes.","Surface 'City not found' to the user and re-prompt."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function isResolvableCity(city: string): boolean {\n  // cheap client-side check before calling the geocoder\n  return /^[\\p{L} .'-]+$/u.test(city.trim()) && city.trim().length >= 2\n}","typeGuard":null,"tryCatchPattern":"try {\n  await geocodeCity(city)\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('City not found')) {\n    // prompt user to re-enter / disambiguate the city\n  } else throw e\n}","preventionTips":["Autocomplete city names from a known list when possible.","Strip diacritics/whitespace and try alternate spellings on not-found.","Surface 'City not found' as a recoverable prompt, not a crash."],"tags":["weather","geocoding","validation","not-found","user-input"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}