{"record":{"id":"8f9de2550096faf4","repo":"jackwener/OpenCLI","slug":"label-returned-http-resp-status-8f9de2","errorCode":null,"errorMessage":"${label} returned HTTP ${resp.status}","messagePattern":"(.+?) returned HTTP (.+?)","errorType":"http","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/semanticscholar/utils.js","lineNumber":122,"sourceCode":"        if (resp.status === 429 && attempt === 0 && !apiKey) {\n            attempt += 1;\n            await new Promise(resolve => setTimeout(resolve, 1500));\n            continue;\n        }\n        break;\n    }\n\n    if (resp.status === 404) {\n        throw new EmptyResultError(label, `Semantic Scholar returned 404 for ${url}.`);\n    }\n    if (resp.status === 429) {\n        throw new CommandExecutionError(\n            `${label} returned HTTP 429 (rate limited)`,\n            'Semantic Scholar throttles anonymous traffic; set SEMANTIC_SCHOLAR_API_KEY (free at https://www.semanticscholar.org/product/api) or wait a minute 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    } catch (err) {\n        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);\n    }\n    if (body && typeof body === 'object' && body.error) {\n        throw new CommandExecutionError(`${label} returned an error: ${body.error}`);\n    }\n    return body;\n}\n\n/** Return the AI-generated one-line summary if present, else ''. */\nexport function tldrText(tldr) {\n    if (tldr && typeof tldr === 'object' && typeof tldr.text === 'string') {\n        return tldr.text.trim();\n    }","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/semanticscholar/utils.js#L104-L140","documentation":"s2Fetch in clis/semanticscholar/utils.js wraps every Semantic Scholar API call. After handling 404 and 429 specially, any other non-2xx status falls through to this generic `CommandExecutionError` with the raw HTTP status code in the message. It signals the Semantic Scholar graph/recommendations API rejected the request for a reason not otherwise classified (e.g. 400 bad field list, 403 forbidden key, 5xx server outage).","triggerScenarios":"Any s2Fetch call where api.semanticscholar.org responds with a status other than 404 or 429 and !resp.ok: malformed query params rejected with 400, invalid/expired SEMANTIC_SCHOLAR_API_KEY yielding 403, or upstream 500/502/503 outages.","commonSituations":"Requesting a field the API doesn't expose (400), a revoked API key (403), or transient Semantic Scholar server errors during partial outages; also hits when an unauthenticated client is IP-blocked (403) rather than merely throttled.","solutions":["Log or inspect resp.status in the message to identify the specific failure code.","For 400: check the paper ref/fields in the URL; validate refs with requirePaperRef semantics (paperId, DOI, arXiv, or prefixed id).","For 403: verify SEMANTIC_SCHOLAR_API_KEY is valid and not expired; request a free key at https://www.semanticscholar.org/product/api.","For 5xx: wait and retry; check Semantic Scholar status; add backoff/retry around the command.","Confirm network/proxy access to api.semanticscholar.org."],"exampleFix":"// before (no key, hitting 403 on authenticated-only endpoint)\nawait s2Fetch(`${S2_GRAPH_BASE}/paper/${ref}?fields=title`, 'paper');\n// after (attach key and handle non-ok status explicitly)\nprocess.env.SEMANTIC_SCHOLAR_API_KEY = 'your-key';\ntry {\n  await s2Fetch(`${S2_GRAPH_BASE}/paper/${ref}?fields=title`, 'paper');\n} catch (e) {\n  if (/HTTP 403/.test(e.message)) console.error('Check SEMANTIC_SCHOLAR_API_KEY');\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// Validate ref and key presence before calling\nif (!/^(ARXIV|MAG|ACL|PMID|PMCID|URL|CorpusId|DBLP):|^10\\.|^[0-9a-f]{40}$/i.test(ref) && !/^\\d{4}\\.\\d{4,5}/.test(ref)) {\n  throw new Error(`Unrecognised paper ref: ${ref}`);\n}\nconst hasKey = Boolean(process.env.SEMANTIC_SCHOLAR_API_KEY);","typeGuard":"function isS2Ref(ref) {\n  return typeof ref === 'string' && (/^[0-9a-f]{40}$/i.test(ref.trim()) || /^(ARXIV|MAG|ACL|PMID|PMCID|URL|CorpusId|DBLP):/i.test(ref.trim()) || /^10\\./.test(ref.trim()) || /^\\d{4}\\.\\d{4,5}(v\\d+)?$/.test(ref.trim()));\n}","tryCatchPattern":"try {\n  const data = await s2Fetch(url, 'paper');\n} catch (err) {\n  const m = /HTTP (\\d{3})/.exec(err.message);\n  if (m && +m[1] >= 500) return retryWithBackoff(() => s2Fetch(url, 'paper'), 3);\n  if (m && +m[1] === 403) console.error('Check SEMANTIC_SCHOLAR_API_KEY');\n  throw err;\n}","preventionTips":["Set SEMANTIC_SCHOLAR_API_KEY to avoid anonymous throttling and 403s.","Validate paper refs (DOI/arXiv/prefixed id) before building request URLs.","Only request fields that the endpoint actually supports.","Wrap calls with backoff for 5xx responses.","Monitor Semantic Scholar status for ongoing outages."],"tags":["http","api","network","semantic-scholar"],"backgroundTag":"http-non-ok-status","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}