{"record":{"id":"7cfb78d38ae36229","repo":"jackwener/OpenCLI","slug":"hf-paper-returned-http-429-rate-limited","errorCode":null,"errorMessage":"hf paper returned HTTP 429 (rate limited)","messagePattern":"hf paper returned HTTP 429 \\(rate limited\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":429,"severity":"warning","filePath":"clis/hf/paper.js","lineNumber":45,"sourceCode":"            throw new ArgumentError(\n                `hf paper id \"${args.id}\" is not a valid arXiv id`,\n                'Expected the modern arXiv form `YYMM.NNNNN` (optionally with a version suffix like `v3`).',\n            );\n        }\n        const endpoint = process.env.HF_ENDPOINT?.replace(/\\/+$/, '') || 'https://huggingface.co';\n        const url = `${endpoint}/api/papers/${encodeURIComponent(raw)}`;\n        let resp;\n        try {\n            resp = await fetch(url, { headers: { accept: 'application/json' } });\n        }\n        catch (err) {\n            throw new CommandExecutionError(`hf paper request failed: ${err?.message ?? err}`);\n        }\n        if (resp.status === 404) {\n            throw new EmptyResultError('hf paper', `Hugging Face has no paper page for \"${raw}\".`);\n        }\n        if (resp.status === 429) {\n            throw new CommandExecutionError(\n                'hf paper returned HTTP 429 (rate limited)',\n                'Hugging Face throttles unauthenticated traffic; wait a few seconds and retry.',\n            );\n        }\n        if (!resp.ok) {\n            throw new CommandExecutionError(`hf paper returned HTTP ${resp.status}`);\n        }\n        let body;\n        try {\n            body = await resp.json();\n        }\n        catch (err) {\n            throw new CommandExecutionError(`hf paper returned malformed JSON: ${err?.message ?? err}`);\n        }\n        if (!body || typeof body !== 'object' || !body.id) {\n            throw new EmptyResultError('hf paper', `Hugging Face returned no paper data for \"${raw}\".`);\n        }\n        const authors = Array.isArray(body.authors)","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/hf/paper.js#L27-L63","documentation":"CommandExecutionError('hf paper returned HTTP 429 (rate limited)') thrown when Hugging Face responds 429 to the unauthenticated /api/papers request. The library calls out that HF throttles unauthenticated traffic and the fix is simply to wait and retry — no retry/backoff is performed automatically.","triggerScenarios":"GET /api/papers/<id> returns HTTP 429 because the client IP exceeded HF's anonymous rate limit — typically after issuing many hf/hf-paper queries in quick succession or running the command in a loop/script.","commonSituations":"Batch scripts iterating over many paper ids; shared CI runner IPs already throttled by HF; running the command repeatedly while debugging; VPN/proxy egress IP shared by many users.","solutions":["Wait a few seconds (or longer, per any Retry-After header) and rerun the command.","Add backoff/jitter between calls if scripting many lookups (e.g. sleep 2 between invocations).","Set HF_ENDPOINT to an authenticated or less-throttled mirror if available and permitted.","Reduce parallelism — run lookups sequentially rather than in parallel loops.","Check whether a shared egress IP (VPN, corporate proxy, CI runner) is the source and switch networks if possible."],"exampleFix":"// before (shell loop, no delay)\nfor id in $(cat ids.txt); do opencli hf paper $id; done\n// after\nfor id in $(cat ids.txt); do opencli hf paper $id; sleep 2; done","handlingStrategy":"retry","validationCode":"// throttle client-side before calling: at most 1 request per 2s\nconst MIN_INTERVAL_MS = 2000;\nlet last = 0;\nasync function throttledRun(id) {\n  const wait = Math.max(0, last + MIN_INTERVAL_MS - Date.now());\n  await new Promise(r => setTimeout(r, wait));\n  last = Date.now();\n  return run(['opencli', 'hf paper', id]);\n}","typeGuard":"function isRateLimited(e) {\n  return e instanceof Error && /HTTP 429/.test(e.message);\n}","tryCatchPattern":"async function withRetry(fn, attempts = 5) {\n  for (let i = 0; i < attempts; i++) {\n    try { return await fn(); }\n    catch (e) {\n      if (/HTTP 429/.test(e.message) && i < attempts - 1) {\n        await new Promise(r => setTimeout(r, 2 ** i * 1000 + Math.random() * 500));\n        continue;\n      }\n      throw e;\n    }\n  }\n}","preventionTips":["Serialize hf paper lookups with a delay (e.g. sleep 2) in scripts.","Avoid parallel fan-out against HF's anonymous API.","Prefer authenticated or mirrored endpoints when doing bulk lookups.","Watch for 429s on shared CI/VPN egress IPs and add backoff.","Cache paper results locally to avoid repeat queries."],"tags":["rate-limit","http-429","huggingface","cli"],"backgroundTag":"http-429-rate-limited","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}