{"record":{"id":"a31915438caeb419","repo":"yamadashy/repomix","slug":"github-api-rate-limit-exceeded-resetdate-rat","errorCode":null,"errorMessage":"GitHub API rate limit exceeded. ${resetDate ? `Rate limit resets at ${resetDate.toISOString()}` : 'Please try again later.'}","messagePattern":"GitHub API rate limit exceeded\\. (.+?)` : 'Please try again later\\.'\\}","errorType":"http","errorClass":"RepomixError","httpStatus":403,"severity":"error","filePath":"src/core/git/gitHubArchiveApi.ts","lineNumber":52,"sourceCode":"  return null;\n};\n\n/**\n * Checks if a response indicates a GitHub API rate limit or error\n */\nexport const checkGitHubResponse = (response: Response): void => {\n  if (response.status === 404) {\n    throw new RepomixError(\n      'Repository not found or is private. Please check the repository URL and your access permissions.',\n    );\n  }\n\n  if (response.status === 403) {\n    const rateLimitRemaining = response.headers.get('X-RateLimit-Remaining');\n    if (rateLimitRemaining === '0') {\n      const resetTime = response.headers.get('X-RateLimit-Reset');\n      const resetDate = resetTime ? new Date(Number.parseInt(resetTime, 10) * 1000) : null;\n      throw new RepomixError(\n        `GitHub API rate limit exceeded. ${resetDate ? `Rate limit resets at ${resetDate.toISOString()}` : 'Please try again later.'}`,\n      );\n    }\n    throw new RepomixError(\n      'Access denied. The repository might be private or you might not have permission to access it.',\n    );\n  }\n\n  if (response.status === 500 || response.status === 502 || response.status === 503 || response.status === 504) {\n    throw new RepomixError('GitHub server error. Please try again later.');\n  }\n\n  if (!response.ok) {\n    throw new RepomixError(`GitHub API error: ${response.status} ${response.statusText}`);\n  }\n};\n","sourceCodeStart":34,"sourceCodeEnd":69,"githubUrl":"https://github.com/yamadashy/repomix/blob/f465ad909315a22120636baf03fa5e28701a50cb/src/core/git/gitHubArchiveApi.ts#L34-L69","documentation":"When GitHub replies 403 with the X-RateLimit-Remaining header at 0, the unauthenticated API rate limit (60 requests/hour per IP) has been exhausted. The error includes the exact reset time from X-RateLimit-Reset when the header is present.","triggerScenarios":"A GitHub API request returns HTTP 403 and header X-RateLimit-Remaining: 0 — too many remote-packing requests from one IP/token within the rate-limit window.","commonSituations":"CI runners sharing one egress IP hitting the 60/hour anonymous limit; scripts looping over many repos without a token; a shared office/NAT IP already exhausted by other users.","solutions":["Set a GitHub token to raise the limit to 5,000/hour: `export GITHUB_TOKEN=ghp_...` and re-run.","Wait until the reset time printed in the error message, then retry.","Cache repacked output and avoid re-packing unchanged repos in loops/CI to reduce request volume."],"exampleFix":"// before\nnpx repomix --remote https://github.com/user/repo   // 403 rate limit (60/hr)\n// after\nexport GITHUB_TOKEN=ghp_yourToken\nnpx repomix --remote https://github.com/user/repo   // 5000/hr","handlingStrategy":"retry","validationCode":"const remaining = await fetch('https://api.github.com/rate_limit', {\n  headers: process.env.GITHUB_TOKEN ? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } : {}\n}).then(r => r.json());\nif (remaining.resources.core.remaining === 0) {\n  throw new Error('GitHub rate limit exhausted; wait until ' + new Date(remaining.resources.core.reset * 1000).toISOString());\n}","typeGuard":null,"tryCatchPattern":"try {\n  await pack({ remote: url });\n} catch (e) {\n  if (e instanceof RepomixError && e.message.includes('rate limit exceeded')) {\n    const reset = e.message.match(/resets at (.+?)'/)?.[1];\n    console.error(`Rate limited; retry after ${reset ?? 'the reset window'}`);\n  } else throw e;\n}","preventionTips":["Always set GITHUB_TOKEN in CI and scripts to get the 5,000/hour limit instead of 60/hour per IP.","Check the printed reset time and schedule retries after it.","Batch repo processing and cache outputs instead of re-packing repeatedly.","Avoid sharing one egress IP across many unauthenticated automation jobs."],"tags":["github","rate-limit","http-403","api"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"f465ad909315a22120636baf03fa5e28701a50cb","analyzedAt":"2026-08-29T01:27:42.024Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}