{"record":{"id":"259239ef2740f608","repo":"jackwener/OpenCLI","slug":"label-returned-http-resp-status-259239","errorCode":null,"errorMessage":"${label} returned HTTP ${resp.status}","messagePattern":"(.+?) returned HTTP (.+?)","errorType":"http","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/rubygems/utils.js","lineNumber":68,"sourceCode":"        resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });\n    }\n    catch (err) {\n        throw new CommandExecutionError(\n            `${label} request failed: ${err?.message ?? err}`,\n            'Check that rubygems.org is reachable from this network.',\n        );\n    }\n    if (resp.status === 404) {\n        throw new EmptyResultError(label, `RubyGems returned 404 for ${url}.`);\n    }\n    if (resp.status === 429) {\n        throw new CommandExecutionError(\n            `${label} returned HTTP 429 (rate limited)`,\n            'RubyGems throttles bursts; wait a few seconds and retry.',\n        );\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    }\n    catch (err) {\n        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);\n    }\n    return body;\n}\n\n/** Trim \"2026-03-24T20:27:42.098Z\" → \"2026-03-24T20:27:42Z\" so timestamps share a uniform precision. */\nexport function trimDate(value) {\n    const s = String(value ?? '').trim();\n    if (!s) return null;\n    const noFrac = s.replace(/\\.\\d+/, '');\n    return noFrac.endsWith('Z') ? noFrac : `${noFrac}Z`;\n}","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/rubygems/utils.js#L50-L86","documentation":"gemsFetch (clis/rubygems/utils.js:68) wraps every RubyGems.org REST call. It explicitly handles 404 (EmptyResultError) and 429 (rate-limit hint), and any other non-OK status falls into this generic CommandExecutionError carrying the raw HTTP status in the message. It signals that rubygems.org answered but with an unhandled error status (e.g. 500, 503, 403).","triggerScenarios":"Any gemsFetch call (gem info, versions, downloads, search) where the fetch succeeded but resp.ok is false and the status is neither 404 nor 429 — e.g. rubygems.org returning 5xx during an outage, a 403 from a proxy/firewall, or a 410 for removed endpoints.","commonSituations":"RubyGems.org incidents/degraded service; corporate proxies or VPNs intercepting requests and returning 403/502; rubygems.org temporarily blocking a user-agent or IP range; transient 502/503 from the CDN in front of rubygems.org.","solutions":["Re-run the command after a short delay — 5xx statuses from rubygems.org are usually transient.","Check https://status.rubygems.org for an ongoing outage.","If you get 403/407, check proxy/VPN configuration and that rubygems.org is reachable (curl the URL directly).","Retry with a different network (e.g. disable corporate proxy) to rule out network interception.","Capture the exact HTTP status in the message and consult RubyGems API docs for that status code."],"exampleFix":"// before\nawait gemsFetch(`${GEMS_BASE}/gems/${name}.json`, 'rubygems gem info');\n// after\ntry {\n  const info = await gemsFetch(`${GEMS_BASE}/gems/${name}.json`, 'rubygems gem info');\n} catch (err) {\n  if (/returned HTTP 5\\d\\d/.test(err.message)) {\n    // retry with backoff or check status.rubygems.org\n  }\n}","handlingStrategy":"retry","validationCode":"// Pre-check service health before batch calls\nconst health = await fetch('https://rubygems.org/api/v1/versions/rails.json');\nif (!health.ok && health.status >= 500) throw new Error('rubygems.org is unhealthy; defer batch');","typeGuard":"function isUnhandledHttpStatus(err) {\n  return err instanceof Error && /returned HTTP \\d{3}/.test(err.message) && !/HTTP (404|429)/.test(err.message);\n}","tryCatchPattern":"try {\n  const info = await gemsFetch(url, 'rubygems gem info');\n} catch (err) {\n  if (/returned HTTP 5\\d\\d/.test(err.message)) {\n    await sleep(2000);\n    return gemsFetch(url, 'rubygems gem info'); // retry with backoff\n  }\n  throw err;\n}","preventionTips":["Add exponential backoff + retry for 5xx in batch jobs.","Check status.rubygems.org before large bulk runs.","Throttle request rate to avoid triggering protective 403/5xx responses.","Keep a custom user-agent so RubyGems can contact you instead of blocking silently."],"tags":["network","http","api","rubygems","server-error"],"backgroundTag":"http-5xx-unexpected-status","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}