{"record":{"id":"9a8a07d1bcedfbaa","repo":"jackwener/OpenCLI","slug":"label-returned-http-resp-status-9a8a07","errorCode":null,"errorMessage":"${label} returned HTTP ${resp.status}.","messagePattern":"(.+?) returned HTTP (.+?)\\.","errorType":"http","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/wttr/utils.js","lineNumber":31,"sourceCode":"        throw new ArgumentError(`--${name} is required`);\n    }\n    return value.trim();\n}\n\nexport async function wttrFetch(location, label) {\n    // wttr.in path-encodes the location. Spaces → %20 is fine; commas survive.\n    const url = `${WTTR_BASE}/${encodeURIComponent(location)}?format=j1`;\n    let resp;\n    try {\n        resp = await fetch(url, { headers: { 'User-Agent': UA, accept: 'application/json' } });\n    } catch (err) {\n        throw new CommandExecutionError(`${label} request failed: ${err.message}`);\n    }\n    if (resp.status === 404) {\n        throw new EmptyResultError(label, `${label} could not find location \"${location}\".`);\n    }\n    if (!resp.ok) {\n        throw new CommandExecutionError(`${label} returned HTTP ${resp.status}.`);\n    }\n    let body;\n    try {\n        body = await resp.json();\n    } catch (err) {\n        // wttr.in falls back to plain-text \"Unknown location\" for some bad inputs;\n        // promote that to EmptyResult instead of pretending we got JSON.\n        throw new EmptyResultError(label, `${label} returned non-JSON body (likely unknown location).`);\n    }\n    return body;\n}\n\n// wttr.in's \"weatherDesc\" / \"lang_en\" fields are arrays of `{ value: '...' }` objects.\n// Single-element 99% of the time but the schema is a list.\nexport function pickWeatherDesc(arr) {\n    if (!Array.isArray(arr) || !arr.length) return '';\n    const first = arr[0];\n    return typeof first?.value === 'string' ? first.value.trim() : '';","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/wttr/utils.js#L13-L49","documentation":"wttrFetch in clis/wttr/utils.js wraps all HTTP calls to wttr.in. After handling fetch network failures and 404s separately, any other non-OK HTTP status (429 rate limit, 5xx server errors, etc.) is raised as a CommandExecutionError with the upstream status code in the message. It signals the wttr.in service itself rejected or failed the request, not that the location was unknown.","triggerScenarios":"Calling wttrFetch (via the wttr CLI's body command) when wttr.in responds with a status other than 200 or 404 — e.g. HTTP 429 when rate-limited, 500/502/503 during wttr.in outages or overload.","commonSituations":"Hammering wttr.in with many rapid requests (it rate-limits aggressively); wttr.in's shared public service being overloaded or down; corporate proxies intercepting the request and returning 403/502; IPv6 connectivity issues causing upstream gateway errors.","solutions":["Retry the request after a short backoff (wttr.in 429/5xx are usually transient).","If the status is 429, slow down request frequency or cache results instead of re-fetching.","Check https://wttr.in directly in a browser to confirm the service is up.","Check local network/proxy configuration that might inject non-200 responses.","Use an alternative weather source (e.g. the NWS CLI for US locations) if wttr.in stays down."],"exampleFix":"// before\nconst weather = await body('--location', 'Berlin');\n// after\ntry {\n  const weather = await body('--location', 'Berlin');\n} catch (err) {\n  if (/returned HTTP (429|5\\d\\d)/.test(err.message)) {\n    await new Promise(r => setTimeout(r, 5000));\n    // retry once\n  } else throw err;\n}","handlingStrategy":"retry","validationCode":"const resp = await fetch('https://wttr.in/Berlin?format=j1');\nif (!resp.ok && resp.status !== 404) {\n  console.warn(`wttr.in unhealthy (HTTP ${resp.status}), use cached data or another source`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const weather = await body('--location', loc);\n} catch (err) {\n  if (/returned HTTP (429|5\\d\\d)/.test(err.message)) {\n    await sleep(backoff);\n    // retry with exponential backoff, fall back to cached data on final failure\n  } else throw err;\n}","preventionTips":["Cache wttr.in responses (they update hourly at most) instead of refetching per call.","Add exponential backoff and a cap of 1-2 retries for 429/5xx.","Monitor wttr.in status before running batch weather jobs.","Avoid tight loops of requests to wttr.in."],"tags":["network","http-error","rate-limit","wttr-in"],"backgroundTag":"http-5xx-upstream-error","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}