{"record":{"id":"f8f5811709b24806","repo":"moeru-ai/airi","slug":"failed-to-fetch-github-releases-atom-atomrespon","errorCode":null,"errorMessage":"Failed to fetch GitHub releases atom (${atomResponse.status} ${atomResponse.statusText})","messagePattern":"Failed to fetch GitHub releases atom \\((.+?) (.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/stage-tamagotchi/src/main/services/electron/auto-updater.ts","lineNumber":433,"sourceCode":"\n      if (!response.ok)\n        throw new Error(`Failed to fetch GitHub releases (${response.status} ${response.statusText})`)\n\n      const payload = await response.json()\n      if (!Array.isArray(payload))\n        throw new Error('Unexpected GitHub releases payload shape')\n\n      const tag = selectLatestTagForLane(payload as GitHubReleaseRecord[], lane)\n      if (tag)\n        return tag\n    }\n    catch (error) {\n      log.withError(error).warn('GitHub releases API lookup failed, trying releases.atom fallback')\n    }\n\n    const atomResponse = await fetch(GITHUB_RELEASES_ATOM_URL)\n    if (!atomResponse.ok)\n      throw new Error(`Failed to fetch GitHub releases atom (${atomResponse.status} ${atomResponse.statusText})`)\n\n    const atom = await atomResponse.text()\n    const releasesFromAtom = extractReleaseTagsFromAtom(atom).map(tag => ({ tag_name: tag }))\n    const tag = selectLatestTagForLane(releasesFromAtom, lane)\n    if (!tag)\n      throw new Error(`No GitHub release found for update lane \"${lane}\"`)\n\n    return tag\n  }\n\n  async function prepareGitHubGenericFeed() {\n    if (activeFeedUrlOverride)\n      return\n    if (resolvedReleaseTag)\n      return\n    if (prepareFeedPromise) {\n      await prepareFeedPromise\n      return","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/apps/stage-tamagotchi/src/main/services/electron/auto-updater.ts#L415-L451","documentation":"Thrown in resolveGitHubReleaseTagForLane when the releases.atom fallback fetch returns a non-ok HTTP status. This is the second-stage fallback after the primary GitHub releases JSON API already failed (its failure was caught and warned). The atom feed is the last resort for auto-update tag resolution.","triggerScenarios":"GitHub is rate-limiting the client (unauthenticated requests), GitHub is down, the network proxy blocks github.com, or the atom URL constant is stale. Both the API and atom endpoints must fail for this to surface — a single endpoint failure is swallowed.","commonSituations":"CI or dev machine behind a corporate proxy; exceeded GitHub unauthenticated rate limit (60/hr); offline dev; GitHub incident; GITHUB_RELEASES_ATOM_URL points to a relocated feed.","solutions":["Check connectivity to github.com and whether a proxy/firewall blocks the atom feed.","Wait if rate-limited — GitHub unauthenticated allowance resets hourly; authenticate requests if a token is available.","Run the update check later during a GitHub platform incident.","Verify GITHUB_RELEASES_ATOM_URL still resolves to the active releases feed."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await resolveGitHubReleaseTagForLane(lane)\n} catch (e) {\n  log.warn('Auto-update tag resolution unavailable, skipping update check', e)\n  // non-fatal — update checks are best-effort\n}","preventionTips":["Treat update-check failures as non-fatal (warn, don't crash).","Authenticate GitHub requests when possible to avoid rate limits.","Cache the last-known release tag so a transient failure doesn't block the app."],"tags":["network","auto-updater","github","rate-limit","fallback"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}