{"record":{"id":"e982752ece1347af","repo":"iOfficeAI/AionUi","slug":"update-errors-githubapitimeout","errorCode":"update.errors.githubApiTimeout","errorMessage":"update.errors.githubApiTimeout","messagePattern":"update\\.errors\\.githubApiTimeout","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/desktop/src/process/bridge/updateBridge.ts","lineNumber":342,"sourceCode":"      headers: {\n        Accept: 'application/vnd.github+json',\n        'User-Agent': DEFAULT_USER_AGENT,\n      },\n      signal: controller.signal,\n    });\n\n    if (!res.ok) {\n      throw new Error((await getI18n()).t('update.errors.githubApiFailed', { status: res.status }));\n    }\n\n    const json = (await res.json()) as unknown;\n    if (!Array.isArray(json)) {\n      throw new Error((await getI18n()).t('update.errors.githubApiNotArray'));\n    }\n    return json as GitHubReleaseApi[];\n  } catch (err: unknown) {\n    if (err instanceof Error && err.name === 'AbortError') {\n      throw new Error((await getI18n()).t('update.errors.githubApiTimeout'), { cause: err });\n    }\n    throw err;\n  } finally {\n    clearTimeout(timeoutId);\n  }\n};\n\nconst CDN_MANIFEST_TIMEOUT_MS = 15000;\nconst GITHUB_NOTES_TIMEOUT_MS = 10000;\n\n/**\n * Fetch and parse the authoritative CDN channel manifest for the current\n * platform/arch. Any failure here fails the manual check — the CDN is the\n * single source of truth for \"is there an update\".\n */\nconst fetchCdnManifest = async (): Promise<CdnLatestManifest> => {\n  const url = `${CDN_BASE_URL}/${resolveCdnChannelFile()}`;\n  const controller = new AbortController();","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/iOfficeAI/AionUi/blob/711aa0550ee183ea495dc33e2c05c7943b70a60a/packages/desktop/src/process/bridge/updateBridge.ts#L324-L360","documentation":"Thrown by fetchGitHubReleases when the AbortController timer (default 30s) fires before the GitHub API responds — the underlying fetch rejects with an AbortError, which is caught and re-thrown as this timeout error with the original error preserved as cause.","triggerScenarios":"Calling fetchGitHubReleases when api.github.com takes longer than timeoutMs (default 30000) to respond: slow/high-latency links, GitHub degradation, large response over constrained bandwidth, or blocking middleware that hangs the socket.","commonSituations":"Firewalled environments where api.github.com is blackholed (connection opens but never responds); VPN routes with huge latency; GitHub partial outages; CI runners with restricted egress that silently stall instead of rejecting.","solutions":["Retry — transient network slowness is the most common cause","Verify api.github.com is reachable (curl -m 10 https://api.github.com) and not blocked by firewall/proxy","If on a legitimately slow link, pass a larger timeoutMs to fetchGitHubReleases","Check GitHub status page for degradation","Fix VPN/DNS rules that blackhole the API host"],"exampleFix":"// before\nconst releases = await fetchGitHubReleases('aionui/aionui'); // 30s cap\n\n// after\nconst releases = await fetchGitHubReleases('aionui/aionui', 90000);","handlingStrategy":"retry","validationCode":"// pre-flight reachability check (best effort)\nawait Promise.race([fetch('https://api.github.com', { method: 'HEAD' }), sleep(4000)]);","typeGuard":null,"tryCatchPattern":"try {\n  const releases = await fetchGitHubReleases(repo, timeoutMs);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('githubApiTimeout')) {\n    await backoff(2);\n    const releases = await fetchGitHubReleases(repo, timeoutMs * 2);\n  } else throw err;\n}","preventionTips":["Pass a generous timeoutMs on slow links","Pre-flight-check api.github.com reachability at app start","Retry with exponential backoff — timeouts are usually transient"],"tags":["timeout","github-api","network","updater"],"backgroundTag":"request-timeout","analyzedSha":"711aa0550ee183ea495dc33e2c05c7943b70a60a","analyzedAt":"2026-08-28T07:56:06.558Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}