aaif-goose/goose · error
GitHub API returned ${response.status}: ${response.statusTex
Error message
GitHub API returned ${response.status}: ${response.statusText} What it means
githubUpdater fetches the latest release from the GitHub releases API; any non-2xx response throws with the HTTP status and status text. The response body is logged before throwing. The two dominant causes are rate limiting (403 with X-RateLimit-Remaining: 0 for unauthenticated clients — 60 req/hour per IP) and a 404 because the configured owner/repo is wrong or the release is private without a token.
Source
Thrown at ui/desktop/src/utils/githubUpdater.ts:67
const response = await fetch(this.apiUrl, {
headers: {
Accept: 'application/vnd.github.v3+json',
'User-Agent': `Goose-Desktop/${app.getVersion()}`,
},
signal: controller.signal,
});
clearTimeout(timeoutId);
const fetchDuration = Date.now() - startTime;
log.info(
`GitHubUpdater: GitHub API response status: ${response.status} ${response.statusText} (took ${fetchDuration}ms)`
);
if (!response.ok) {
const errorText = await response.text();
log.error(`GitHubUpdater: GitHub API error response: ${errorText}`);
throw new Error(`GitHub API returned ${response.status}: ${response.statusText}`);
}
const release: GitHubRelease = await safeJsonParse<GitHubRelease>(
response,
'Failed to get GitHub release information'
);
log.info(`GitHubUpdater: Found release: ${release.tag_name} (${release.name})`);
log.info(`GitHubUpdater: Release published at: ${release.published_at}`);
log.info(`GitHubUpdater: Release assets count: ${release.assets.length}`);
const latestVersion = release.tag_name.replace(/^v/, ''); // Remove 'v' prefix if present
const currentVersion = app.getVersion();
log.info(
`GitHubUpdater: Current version: ${currentVersion}, Latest version: ${latestVersion}`
);
// Compare versionsView on GitHub (pinned to 3810898a74)
Solutions
- If 403: wait for the rate-limit window to reset (check X-RateLimit-Reset) or supply an authenticated request/GITHUB_TOKEN so the limit rises to 5000/h
- If 404: verify the owner/repo the updater queries and that the latest release exists and is public
- If 5xx: retry with backoff — GitHub API transient failures are common
- Cache release-check results to avoid re-querying on every launch
Example fix
// before
const response = await fetch(releaseApiUrl);
// after (fail fast on rate limit, keep body details)
const response = await fetch(releaseApiUrl);
if (response.status === 403 || response.status === 429) {
const reset = response.headers.get('x-ratelimit-reset');
log.warn(`Rate limited until ${reset}`);
} Defensive patterns
Strategy: retry
Validate before calling
// Check rate-limit headers before treating failure as fatal:
const response = await fetch(apiUrl);
const remaining = Number(response.headers.get('x-ratelimit-remaining') ?? '1');
if (remaining <= 1) scheduleNextCheckAfterReset(response.headers.get('x-ratelimit-reset')); Try / catch
async function checkWithBackoff(retries = 3): Promise<GitHubRelease> {
for (let i = 0; i <= retries; i++) {
try {
return await checkLatestRelease();
} catch (e) {
const s = String(e);
const rateLimited = s.includes(' 403') || s.includes(' 429');
if (i === retries || (rateLimited && !hasToken)) throw e;
await new Promise(r => setTimeout(r, 2 ** i * 1000));
}
}
throw new Error('unreachable');
} Prevention
- Cache release metadata with a TTL instead of checking every launch/hour
- Send an Authorization header in managed deployments to lift the 60/hr unauthenticated cap
- Treat 404 as config error (check owner/repo) and 403/429 as rate limit — different remedies
When it happens
Trigger: checkForUpdates via GitHub fallback after electron-updater failed; more than 60 unauthenticated API calls/hour (shared NAT IPs amplify this); wrong GITHUB owner/repo in updater config; private repo fetched without authorization; GitHub incident returning 5xx.
Common situations: Corporate NAT pooling many users behind one IP; misconfigured repo after a rename/transfer; CI runs hammering the API; release not yet published when the client checks.
Related errors
- Download failed: ${response.status} ${response.statusText}
- HTTP error! status: ${response.status}
- Update Available but no download URL found for platform: ${p
- Response body is null
- GitHub API request failed: {}
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/664ad38f3f4cbead.
Report an issue: GitHub.