{"record":{"id":"c96b394091f8be96","repo":"jackwener/OpenCLI","slug":"label-returned-http-429-rate-limited-c96b39","errorCode":null,"errorMessage":"${label} returned HTTP 429 (rate limited)","messagePattern":"(.+?) returned HTTP 429 \\(rate limited\\)","errorType":"http","errorClass":"CommandExecutionError","httpStatus":429,"severity":"error","filePath":"clis/maven/utils.js","lineNumber":86,"sourceCode":"    return { groupId, artifactId, version: version ?? null };\n}\n\nexport async function mavenFetch(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 search.maven.org is reachable from this network.',\n        );\n    }\n    if (resp.status === 404) {\n        throw new EmptyResultError(label, `Maven Central returned 404 for ${url}.`);\n    }\n    if (resp.status === 429) {\n        throw new CommandExecutionError(\n            `${label} returned HTTP 429 (rate limited)`,\n            'Maven Central throttles bursts; wait a few seconds 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    }\n    catch (err) {\n        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);\n    }\n    return body;\n}\n\n/** Convert epoch-ms (Maven Solr `timestamp`) to ISO-8601 UTC. Returns null for falsy/invalid. */","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/maven/utils.js#L68-L104","documentation":"mavenFetch() detects HTTP 429 from search.maven.org and throws a CommandExecutionError indicating the request was rate limited. Maven Central's Solr endpoint throttles bursts of requests.","triggerScenarios":"Making many maven lookups in rapid succession (batch scripts, CI loops, fan-out queries) until search.maven.org responds 429.","commonSituations":"Iterating over hundreds of dependencies with no delay; shared CI runners where many jobs hit the same unauthenticated endpoint; retry loops without backoff amplifying the throttling.","solutions":["Wait a few seconds and retry — the throttle is temporary.","Add exponential backoff with jitter around mavenFetch calls.","Rate-limit your own requests (e.g. a few hundred ms between lookups).","Batch queries where possible (Solr rows/q parameter) instead of one request per coordinate."],"exampleFix":"// before\nfor (const c of coords) results.push(await lookup(c));\n// after\nfor (const c of coords) {\n  results.push(await withBackoff(() => lookup(c)));\n  await sleep(250); // stay under Maven Central rate limits\n}","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"async function withBackoff(fn, attempts = 4) {\n  for (let i = 0; ; i++) {\n    try { return await fn(); }\n    catch (err) {\n      if (!/429/.test(err.message) || i >= attempts) throw err;\n      await sleep(2 ** i * 500 + Math.random() * 250);\n    }\n  }\n}\nconst data = await withBackoff(() => mavenFetch(url, 'search'));","preventionTips":["Throttle your own request rate (e.g. 200-500ms between calls).","Use exponential backoff with jitter on any 429.","Batch queries into fewer Solr requests instead of per-coordinate calls.","Avoid tight retry loops — they prolong the throttle."],"tags":["rate-limit","http-429","maven","retry"],"backgroundTag":"http-429-rate-limited","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}