Repository navigation
installer: name why GitHub's API refused, and retry a refused token once without it - #1890
Merged
Merged
Conversation
…nce without it Every failed release lookup used to print one sentence for a spent rate limit, a rejected token, a forbidden repository, an outage and a dead network, and it advised exporting GITHUB_TOKEN even when the exported token was the cause. http_get kept only the status, so the reason GitHub states on the response (x-ratelimit-remaining, x-ratelimit-reset, the body's message) was thrown away. The installer now keeps each API response's headers and body and names the refusal: the rate limit with the local time it lifts, a rejected token, access, a repository GitHub cannot find, a server fault, or an unreachable host. A token GitHub refuses with 401, 403 or 429 is set aside and the same lookup is asked once without it, because the anonymous quota is a separate bucket; when that works the install goes on with a one-line note. Downloads still never carry the token. The classifiers are pure functions between marker lines, and the tests source that block directly. Fixes #1889. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… lookup The chat manual had no page for an installer that stopped on GitHub's API, and the GUIDE said a token only raises the anonymous limit. running-from-the-terminal now quotes the rate-limit, rejected-token and access sentences, the note printed when a refused token is set aside, and the VERSION pin that skips the lookup, with probes in a person's own words that must reach it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…inventing a wait A 38-digit x-ratelimit-reset slipped past GNU date's refusal into bash's printf fallback, which renders it as the epoch's first second, so the message named a reset time GitHub never sent. A Retry-After that long overflowed BusyBox awk into negative minutes. The reset now has at most eleven digits and Retry-After at most six, and anything longer reads as no number, which says "for up to an hour". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AbirAbbas
added a commit
that referenced
this pull request
Oct 22, 2026
…nce without it (#1890) Hotfix of #1890 onto v0.8.1 for the main install line. When GitHub's API refused the release lookup, the installer printed one sentence for a spent rate limit, a rejected token, refused access, an outage and a dead network, and told people who had exported a token to export one. It now keeps each API response's headers and body, names the refusal with the local time a rate limit lifts, and, when GitHub refuses a token with 401, 403 or 429, asks the same lookup once without it because the anonymous quota is a separate bucket. scripts/install.sh and internal/release/install_test.go are taken byte for byte from #1890's head, so they also carry the installer half of #1832 that staging has served since 2026-10-14: the installer no longer asks the repository's former name after a 404, because that name is only GitHub's redirect to the same repository. The manual, GUIDE and probe changes are #1890's hunks alone. Fixes #1889. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AbirAbbas
added a commit
that referenced
this pull request
Oct 22, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AbirAbbas
added a commit
that referenced
this pull request
Oct 23, 2026
v0.8.2 is v0.8.1 plus the installer hotfix #1890 (371d7f1), which also carried #1832's installer half: the installer no longer asks the repository's former name after a 404. #1832's own entry stays loose on dev and staging for the release that ships the rest of it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AbirAbbas
added a commit
that referenced
this pull request
Oct 23, 2026
Adds the v0.8.2 section to CHANGELOG.md and removes #1890's entry, which v0.8.2 released. Keeps staging and main ancestors of dev. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Fixes #1889.
What was wrong
When GitHub's API refused the release lookup,
scripts/install.shprinted one sentence for every case: a spent rate limit, a rejected token, a forbidden repository, an outage and a dead network.http_getkept only the status code and discarded the headers and body that say which case it was. The adviceor export GITHUB_TOKENwas backwards when an exported token was the cause. A token-bearing request that GitHub refused also aborted the install, even though the anonymous quota is a separate bucket.What it does now
-D, and wget via-Splus--content-on-errorwhere that wget offers the flag.401→ rejected token429, or a403withx-ratelimit-remaining: 0or arate limitbody → rate limit403→ access404→ missing5xx→ serverx-ratelimit-resetand shows it in the host's local time. Without that header it falls back toRetry-After(for about N minutes), and with neither it saysfor up to an hour.Authorization. If that works, the install goes on with one note:GitHub refused GITHUB_TOKEN (401: Bad credentials); continuing without it. If it fails, the message names both attempts.GH_TOKENwhen that is the variable that supplied the token.releases.atomor HTML, the website'sCHANNEL/INSTALL_NAMEseam is byte-identical, and stable'sno stable build has been published yetstays when no token was set aside.[[ =~ ]]regex sits in a variable. The awk is POSIX-only (it runs under mawk and BusyBox awk), anddate -dis never tried on BSD or Darwin.Proof
Before and after, against real GitHub, with
GITHUB_TOKEN=bogusand the public repository:The issue's acceptance list, run through the stub at
CODEAF_GITHUB_API(internal/release/install_test.go):Authorization, to the same path. This covers stable and--devdiscovery, over curl and over wget.401with bodyBad credentials: the message names the token as rejected, gives noexport GITHUB_TOKENadvice, and exits 1.403with no rate-limit headers: the message names access, not quota.403: the message shows the reset fromx-ratelimit-resetin local time. The test runs withTZ=IST-5:30and compares against the time Go computes.BEGIN api refusalandEND api refusalin the script) in a bare bash and check them case by case: reason, wait (including redirect header blocks, CRLF, header-name case, and oversized numbers) and message sanitising.Gates:
make pr-readypassed (light gate, tooling acceptance, and freshinternal/manual+internal/release).A Codex review tried to break the change and found no blockers. Its two edge cases are fixed in the third commit: an oversized
x-ratelimit-resetproduced an invented time, and an oversizedRetry-Aftergave negative minutes under BusyBox awk.Limits
401body, so over wget a rejected token reads(401)withoutBad credentials./bin/bash.Manual
internal/manual/chat/running-from-the-terminal.mdhas a new section, "The installer stopped — GitHub API rate limit used up, 403, 401 Bad credentials, GITHUB_TOKEN refused…". It quotes the sentences above, and four new probes must reach it. Thedocs/GUIDE.mdrow forGITHUB_TOKEN/GH_TOKENnow mentions the anonymous retry.🤖 Generated with Claude Code