iOfficeAI/AionUi · error · Error
update.errors.githubApiFailed
update.errors.githubApiFailed
Error message
update.errors.githubApiFailed
What it means
Thrown by fetchGitHubReleases when the GitHub Releases API call to https://api.github.com/repos/{repo}/releases returns a non-OK HTTP status. The status code is interpolated into the message, and the request carries a User-Agent and a 30s AbortController timeout.
Source
Thrown at packages/desktop/src/process/bridge/updateBridge.ts:332
const fetchGitHubReleases = async (repo: string, timeoutMs = 30000): Promise<GitHubReleaseApi[]> => {
const url = `https://api.github.com/repos/${repo}/releases`;
// 添加超时控制,防止网络问题导致无限等待 / Add timeout to prevent infinite wait on network issues
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
try {
const res = await fetch(url, {
headers: {
Accept: 'application/vnd.github+json',
'User-Agent': DEFAULT_USER_AGENT,
},
signal: controller.signal,
});
if (!res.ok) {
throw new Error((await getI18n()).t('update.errors.githubApiFailed', { status: res.status }));
}
const json = (await res.json()) as unknown;
if (!Array.isArray(json)) {
throw new Error((await getI18n()).t('update.errors.githubApiNotArray'));
}
return json as GitHubReleaseApi[];
} catch (err: unknown) {
if (err instanceof Error && err.name === 'AbortError') {
throw new Error((await getI18n()).t('update.errors.githubApiTimeout'), { cause: err });
}
throw err;
} finally {
clearTimeout(timeoutId);
}
};
const CDN_MANIFEST_TIMEOUT_MS = 15000;View on GitHub (pinned to 711aa0550e)
Solutions
- Read the {status} in the message: 403/429 => rate limited, 404 => wrong repo slug, 401 => auth
- Fix the repo string if 404 ('owner/repo' with correct casing/spelling)
- For rate limits, wait or add a GITHUB_TOKEN-capable header and cache release results
- Check https://www.githubstatus.com for 5xx outages
- Verify network/proxy allows api.github.com over HTTPS
Example fix
// before
const releases = await fetchGitHubReleases('aionui/aionui ');
// after
const releases = await fetchGitHubReleases('aionui/aionui'.trim()); Defensive patterns
Strategy: try-catch
Validate before calling
// cheap pre-check that the repo slug is well-formed
const REPO_RE = /^[\w.-]+\/[\w.-]+$/;
if (!REPO_RE.test(repo)) throw new Error('bad repo slug');
await fetchGitHubReleases(repo); Type guard
const isRepoSlug = (s: string): boolean => /^[\w.-]+\/[\w.-]+$/.test(s.trim());
Try / catch
try {
const releases = await fetchGitHubReleases(repo);
} catch (err) {
if (err instanceof Error && err.message.includes('githubApiFailed')) {
const status = /* extract from message */ Number(err.message.match(/\b(\d{3})\b/)?.[1]);
if (status === 403 || status === 429) await sleep(60_000); // rate limited, backoff
else if (status === 404) throw new Error('repo not found');
else await sleep(5_000);
} else throw err;
} Prevention
- Cache GitHub release responses to stay under rate limits
- Validate repo slug format before calling
- Add an auth token header for higher limits in CI
When it happens
Trigger: Calling fetchGitHubReleases for a repo that doesn't exist (404), hitting the rate limit (403/429), bad credentials (401), or a 5xx from GitHub. The message includes the numeric status so the cause is immediately readable.
Common situations: Unauthenticated GitHub API rate limiting (60 req/hr per IP) in CI or shared offices; typo'd owner/repo string; private repo without a token; GitHub incidents returning 5xx; proxy/firewall intercepting api.github.com.
Related errors
- update.errors.githubApiNotArray
- update.errors.githubApiTimeout
- update.errors.cdnManifestFailed
- update.errors.invalidUrl
- update.errors.httpsOnly
AI-assisted analysis of iOfficeAI/AionUi@711aa0550e (2026-08-28).
Data as JSON: /api/errors/81e8802b41875290.
Report an issue: GitHub.