fix(scan github): surface GitHub rate limits instead of silent success - #1426
Open
John-David Dalton (jdalton) wants to merge 1 commit into
Open
Conversation
John-David Dalton (jdalton)
force-pushed
the
jdalton/ask-167-improve-cli-to-handle-github-api-rate-limiting-issues
branch
from
July 24, 2026 21:50
ba7c23e to
349fa46
Compare
Classify GitHub API failures (rate limit, auth, abuse detection) as blocking and short-circuit the repo scan loop and manifest download instead of swallowing them into an ok:true scan of a partial manifest set. Surface an error when every attempted repo fails so scripts do not infer success from ok:true with zero scans created.
John-David Dalton (jdalton)
force-pushed
the
jdalton/ask-167-improve-cli-to-handle-github-api-rate-limiting-issues
branch
from
July 30, 2026 15:21
349fa46 to
96d89e2
Compare
John-David Dalton (jdalton)
enabled auto-merge (squash)
July 30, 2026 16:39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When your GitHub token is rate-limited,
socket scan githubcurrently tells you it succeeded. It exits 0 and prints:Nothing was uploaded. Every repo failed, and the run reported green. On a laptop that is confusing; in CI it is worse, because a pipeline step that exits 0 is a pipeline step nobody looks at. Teams can go a long time believing their repos are being scanned when no scan has happened at all.
After this change, a rate-limited, unauthorized, or abuse-throttled run stops at the first blocking error, prints what hit and — when GitHub tells us — when it resets, and exits non-zero. Genuinely empty repos with no manifests still succeed, exactly as before.
Refs ASK-167.
Why it looked like success — the status code was never read
The GitHub-API scanning path read every GitHub REST response body and JSON-parsed it without ever checking the HTTP status. When a token is rate-limited, GitHub answers with one of three shapes:
403withx-ratelimit-remaining: 0429403with asecondary rate limitbodyNone of those parse into the JSON the code expected, so the old code read them as "repo has no default branch / no manifests". The per-repo error was then swallowed by the scan loop, and the run finished with the success lines above.
The change — classify the response, retry only what is worth retrying, stop the loop on a blocking error
New
utils/github-errors.mtsholds two pieces:classifyGitHubResponsedetects rate-limit, abuse-detection and auth responses and returns a clear, actionableCResulterror. It returns nothing for anything else, so the caller keeps its own handling of 404s, empty repos and the rest.githubApiRequestis a bounded-retry wrapper aroundapiFetch. It waits once and retries when the reset window is short (Retry-Afterorx-ratelimit-resetwithin 30 seconds), surfaces long hourly resets immediately rather than blocking a CLI run on them, retries 5xx and network failures with capped exponential backoff, and never retries an auth failure.Wired in at the call sites:
githubApiRequest. The raw manifest-download host is checked too, so a bulk run that trips the limit mid-download fails loudly instead of counting the file as skipped.runGithubScanLoop, which stops at the first blocking error (rate limit / auth / abuse) and returnsok: false, giving a non-zero exit. A run where every repo failed is also no longer reported as success.The success line now reads
N GitHub repos processedrather thanN GitHub repos detected, since "detected" was part of what made the old output read as a completed scan.GitHub rate limit exceeded …What I checked — 25 tests, no network and no module mocks
src/utils/github-errors.test.mtsandsrc/commands/scan/create-scan-from-github.test.mts. FakefetchandscanRepoFnare injected as plain functions rather than mocked at the module level, so the tests exercise the real decision logic.They cover detection of
403+remaining: 0,429, secondary-limit and401;Retry-Afterand reset parsing; the cheap-retry-then-succeed path; 5xx backoff; the loop stopping on a blocking error and returning a non-zero exit; and an empty repo still succeeding.Ran:
tsgo,eslint, andbiomeare clean on the changed files.Branch scope — this is the
v1.xport;mainalready has the equivalent fixmainalready carries an equivalent Octokit-based fix, so no companion PR is needed there.This ports the same behavior to the shipping
v1.xline, adapted to its raw-apiFetcharchitecture.Note
Medium Risk
Changes CLI exit semantics and GitHub request handling for a CI-facing scan path; behavior is well covered by 25 unit tests with injected fakes.
Overview
Fixes ASK-167:
socket scan githubno longer exits successfully when GitHub rate limits, auth failures, or abuse detection block the run.Adds
utils/github-errors.mtswithclassifyGitHubResponse(rate limit / auth / abuse),githubApiRequest(bounded retries for short reset windows, 5xx, and network errors), and canonical blocking error messages. Repo details, tree, commit, and contents calls usegithubApiRequest; manifest download responses also run throughclassifyGitHubResponse.Extracts
runGithubScanLoopso multi-repo scans stop early on blocking GitHub errors, returnok: false(non-zero exit), and fail when every repo errors for non-blocking reasons instead of reporting "N repos / 0 manifests" as success. Empty repos and partial success behavior are unchanged.Reviewed by Cursor Bugbot for commit 30806f1. Configure here.