{"record":{"id":"570ada3f2428a978","repo":"jackwener/OpenCLI","slug":"stack-exchange-http-resp-status-body-resp","errorCode":null,"errorMessage":"stack exchange HTTP ${resp.status}: ${body || resp.statusText}","messagePattern":"stack exchange HTTP (.+?): (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/stackoverflow/utils.js","lineNumber":68,"sourceCode":"    let resp;\n    try {\n        resp = await fetch(url, {\n            headers: {\n                'Accept': 'application/json',\n                'Accept-Encoding': 'gzip',\n                'User-Agent': UA,\n            },\n        });\n    } catch (error) {\n        throw new CommandExecutionError(`stack exchange request failed: ${error?.message || error}`);\n    }\n    if (resp.status === 429) {\n        throw new CommandExecutionError('stack exchange returned HTTP 429 (rate limited)', 'Wait a few seconds and retry, or lower --limit.');\n    }\n    if (!resp.ok) {\n        let body = '';\n        try { body = (await resp.json())?.error_message || ''; } catch { /* ignore */ }\n        throw new CommandExecutionError(`stack exchange HTTP ${resp.status}: ${body || resp.statusText}`);\n    }\n    let data;\n    try {\n        data = await resp.json();\n    } catch (error) {\n        throw new CommandExecutionError(`stack exchange returned malformed JSON: ${error?.message || error}`);\n    }\n    if (data?.error_id) {\n        throw new CommandExecutionError(\n            `stack exchange API error: ${data.error_message || data.error_name}`,\n            'Inspect the URL in a browser for the canonical error context.',\n        );\n    }\n    return data;\n}\n\n/** Convert SE epoch seconds to YYYY-MM-DD. */\nexport function epochToDate(value) {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/stackoverflow/utils.js#L50-L86","documentation":"CommandExecutionError thrown by seFetch for any non-OK HTTP status other than 429. It attempts to parse the response JSON and surface the API's `error_message`; if that fails it falls back to the HTTP statusText. Typical statuses: 400 (bad parameter), 404 (bad path/id), 503 (SE maintenance).","triggerScenarios":"Malformed API request producing SE error 400 (e.g. invalid sort/pagesize combination); requesting a path that doesn't exist (404); Stack Exchange returning 500/503 during incidents or maintenance windows.","commonSituations":"Stack Exchange API incidents (status.stackoverflow.com); hand-constructed paths with unencoded characters; version drift if SE changes endpoint requirements; intermediary proxies returning HTML error pages (then error_message is empty and only statusText shows).","solutions":["Read the embedded error_message in the thrown message — SE error bodies usually state the exact bad parameter.","Retry later on 5xx; check https://www.stackstatus.com for outages.","Ensure ids are encodeURIComponent'd and paths match the 2.3 API (see utils.js SE_API).","If a proxy intercepts (statusText like 'Forbidden' with no error_message), bypass or reconfigure the proxy."],"exampleFix":"// before: assuming any failure is transient\nawait seFetch(path);\n// after\ncatch (e) {\n  const m = /stack exchange HTTP (\\d+)/.exec(e.message);\n  if (m && Number(m[1]) >= 500) return retryWithBackoff(path);\n  throw e; // 4xx: fix the request\n}","handlingStrategy":"try-catch","validationCode":"// validate before calling: ids numeric, paths encoded\nif (!/^\\/questions\\/[\\d;]+$/.test(path)) throw new TypeError(`unexpected SE path: ${path}`);","typeGuard":null,"tryCatchPattern":"try {\n  return await seFetch(path);\n} catch (e) {\n  const m = /stack exchange HTTP (\\d+)/.exec(String(e.message));\n  if (m) {\n    const status = Number(m[1]);\n    if (status >= 500) return retryWithBackoff(path);           // transient SE-side\n    console.error(`SE rejected the request (${status}): ${e.message}`); // 4xx: fix input\n    process.exitCode = 2;\n    return null;\n  }\n  throw e;\n}","preventionTips":["Read the error_message embedded in the thrown message — SE tells you the bad parameter.","Treat 5xx as transient (retry later; check stackstatus.com) and 4xx as a request bug.","encodeURIComponent dynamic path segments; keep paths aligned with the 2.3 API.","Check SE status pages during widespread failures rather than debugging locally."],"tags":["http-error","stack-exchange-api","api-response"],"backgroundTag":"http-error-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}