{"record":{"id":"7f1f0d926684560b","repo":"jackwener/OpenCLI","slug":"stack-exchange-api-error-data-error-message","errorCode":null,"errorMessage":"stack exchange API error: ${data.error_message || data.error_name}","messagePattern":"stack exchange API error: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/stackoverflow/utils.js","lineNumber":77,"sourceCode":"    } 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) {\n    if (value == null || value === '') return '';\n    const n = Number(value);\n    if (!Number.isFinite(n) || n <= 0) return '';\n    return new Date(n * 1000).toISOString().slice(0, 10);\n}\n\n/** Throw EmptyResultError when an /items array is empty. */\nexport function ensureItems(data, label) {\n    const items = Array.isArray(data?.items) ? data.items : [];","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/stackoverflow/utils.js#L59-L95","documentation":"The Stack Exchange API responded with valid JSON that carries an error_id, meaning the API itself rejected the request (e.g. no site matched, invalid parameter, throttled). seFetch surfaces error_message/error_name verbatim. The second argument hints that opening the URL in a browser shows the canonical error context.","triggerScenarios":"Invalid site parameter (site=nonexistent), missing/invalid key with exceeded anonymous quota (error_id=402 throttle_violation), malformed request parameters rejected by the API.","commonSituations":"Typo'd site name (e.g. site=stackoverflow vs site=stackoverflow needing correct api_site_parameter), anonymous 300-requests-per-day quota exhausted on shared IP, API version path changes.","solutions":["Read error_message in the thrown message and fix the offending parameter (usually `site`)","Check daily quota: anonymous requests are limited to 300/day per IP; register an app key to raise it to 10,000","Open the failing request URL in a browser to see the full API error payload","Verify the site parameter against https://api.stackexchange.com/2.3/sites"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// no meaningful pre-call validation; validate parameters instead:\nif (!/^[a-z]+$/.test(site)) throw new Error(`invalid site: ${site}`);","typeGuard":null,"tryCatchPattern":"try {\n  const data = await seFetch(url);\n} catch (e) {\n  if (/stack exchange API error/.test(e.message)) {\n    if (/throttl|quota/i.test(e.message)) await sleep(backoff);\n    else console.error('Fix request params (usually `site`):', e.message);\n  } else throw e;\n}","preventionTips":["Validate the site name against the /sites endpoint list","Register an API key to avoid anonymous quota throttling","Open the request URL in a browser when debugging","Keep the API version path (2.3) up to date"],"tags":["api","http","stack-exchange","rate-limit"],"backgroundTag":"api-error-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}