{"record":{"id":"e400971313026290","repo":"jackwener/OpenCLI","slug":"label-returned-http-resp-status-e40097","errorCode":null,"errorMessage":"${label} returned HTTP ${resp.status}","messagePattern":"(.+?) returned HTTP (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/rfc/utils.js","lineNumber":52,"sourceCode":"export async function rfcFetch(url, label) {\n    let resp;\n    try {\n        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 datatracker.ietf.org is reachable from this network.',\n        );\n    }\n    if (resp.status === 404) {\n        throw new EmptyResultError(label, `IETF datatracker returned 404 for ${url}.`);\n    }\n    if (resp.status === 429) {\n        throw new CommandExecutionError(`${label} returned HTTP 429 (rate limited)`);\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// IETF datatracker timestamps are like \"2022-02-19 08:46:51\" (no T, no Z)\n// or ISO with offset like \"2016-07-08T21:03:52+00:00\". Normalise to YYYY-MM-DD.\nexport function trimDate(value) {\n    const s = String(value ?? '').trim();\n    if (!s) return null;\n    // Take the first 10 chars only if they form a YYYY-MM-DD prefix.\n    if (/^\\d{4}-\\d{2}-\\d{2}/.test(s)) return s.slice(0, 10);","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/rfc/utils.js#L34-L70","documentation":"rfcFetch throws CommandExecutionError for any datatracker response that is not ok and not one of the specially handled statuses (404, 429). The message includes the label and the HTTP status code so callers know what the server returned.","triggerScenarios":"Datatracker returning 500/502/503 during outages or maintenance, 403 from WAF/permission rules, or redirects/other unexpected non-2xx statuses.","commonSituations":"Datatracker maintenance windows, transient upstream errors (502/503) behind their load balancer, or corporate proxies injecting 403 blocks.","solutions":["Retry after a short delay — 5xx responses are usually transient.","Check the datatracker status page or try the URL in a browser.","Verify no proxy/firewall is intercepting and returning 403.","Catch CommandExecutionError and report resp status with retry advice."],"exampleFix":"// before\nconst doc = await rfcFetch(url, 'rfc 9000'); // may throw on 502\n// after\ntry {\n  const doc = await rfcFetch(url, 'rfc 9000');\n} catch (e) {\n  await sleep(2000);\n  const doc = await rfcFetch(url, 'rfc 9000');\n}","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"async function fetchWithStatusRetry(url, label, attempts = 3) {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      return await rfcFetch(url, label);\n    } catch (err) {\n      const retryable = err instanceof CommandExecutionError && /HTTP 5\\d\\d/.test(err.message);\n      if (!retryable || i === attempts - 1) throw err;\n      await new Promise(r => setTimeout(r, 2 ** i * 1000));\n    }\n  }\n}","preventionTips":["Retry 5xx with exponential backoff; do not retry 403.","Monitor the datatracker status during maintenance windows.","Check proxy/WAF interception if 403s appear consistently.","Alert on non-404/429 statuses in bulk scripts."],"tags":["http-error","server-error","ietf-datatracker"],"backgroundTag":"http-5xx-server-error","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}