{"record":{"id":"1b74e4fda1b3b2f5","repo":"GoogleChrome/lighthouse","slug":"resp-status-fetching-gist","errorCode":null,"errorMessage":"${resp.status} fetching gist","messagePattern":"(.+?) fetching gist","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"viewer/app/src/github-api.js","lineNumber":131,"sourceCode":"          const remaining = Number(resp.headers.get('X-RateLimit-Remaining'));\n          const limit = Number(resp.headers.get('X-RateLimit-Limit'));\n          if (remaining < 10) {\n            logger.warn('Approaching GitHub\\'s rate limit. ' +\n                        `${limit - remaining}/${limit} requests used. Consider signing ` +\n                        'in to increase this limit.');\n          }\n\n          if (!resp.ok) {\n            // Should only be 304 if cachedGist exists and etag was sent, but double check.\n            if (resp.status === 304 && cachedGist) {\n              return Promise.resolve(cachedGist);\n            } else if (resp.status === 404) {\n              // Delete the entry from IDB if it no longer exists on the server.\n              idbKeyval.delete(id); // Note: async.\n            } else if (resp.status === 401 && accessToken) {\n              this._auth.signOut();\n            }\n            throw new Error(`${resp.status} fetching gist`);\n          }\n\n          const etag = resp.headers.get('ETag');\n          return resp.json().then(json => {\n            const gistFiles = Object.keys(json.files);\n            // Attempt to use first file in gist with report extension.\n            let filename = gistFiles.find(filename => filename.endsWith(GithubApi.LH_JSON_EXT));\n            // Otherwise, fall back to first json file in gist\n            if (!filename) {\n              filename = gistFiles.find(filename => filename.endsWith('.json'));\n            }\n            if (!filename) {\n              throw new Error(\n                `Failed to find a Lighthouse report (*${GithubApi.LH_JSON_EXT}) in gist ${id}`\n              );\n            }\n            const f = json.files[filename];\n            if (f.truncated) {","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/GoogleChrome/lighthouse/blob/9515cd4e58ebed69f78742d932b501c2cab8ad8f/viewer/app/src/github-api.js#L113-L149","documentation":"Thrown by GithubApi.getGistFileContentAsJson when the GET /gists/:id response is not OK and not one of the specially handled statuses (304 not-modified served from cache, 404 which deletes the IDB entry, 401 which signs out). Any other failure status (e.g. 403 rate limit, 5xx) reaches this throw with the HTTP status embedded in the message.","triggerScenarios":"Fetching a gist returns a non-OK status other than 304/404/401 — most commonly 403 (rate limited or forbidden) or 500/502/503 server errors.","commonSituations":"Unauthenticated use hitting GitHub's low anonymous rate limit (60 req/hour); token revoked/invalid producing 403; GitHub incident returning 5xx; network proxy returning unexpected codes.","solutions":["Sign in to obtain an access token (raises the rate limit and avoids 403) — the viewer wires this via FirebaseAuth.","On 403/rate-limit, back off and retry after the reset window; surface the X-RateLimit headers (the code already warns near the limit).","Handle 404 by telling the user the gist no longer exists; handle 5xx with a retry."],"exampleFix":"// before\nconst lhr = await githubApi.getGistFileContentAsJson(id);\n\n// after\ntry {\n  const lhr = await githubApi.getGistFileContentAsJson(id);\n} catch (err) {\n  const status = Number(err.message.match(/^(\\d+)/)?.[1]);\n  if (status === 403) showMessage('GitHub rate limit reached — sign in or try later.');\n  else if (status === 404) showMessage('This gist no longer exists.');\n  else showMessage(`Could not load gist: ${err.message}`);\n}","handlingStrategy":"try-catch","validationCode":"// Cannot fully prevent (server-side failures), but reduce 403s by authenticating.\nif (!(await auth.getAccessTokenIfLoggedIn())) {\n  warn('Not signed in — anonymous GitHub rate limit applies (60 req/hour).');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const lhr = await githubApi.getGistFileContentAsJson(id);\n} catch (err) {\n  const status = Number(err.message.match(/^(\\d+)/)?.[1]);\n  if (status === 403) showMessage('GitHub rate limit — sign in or retry later.');\n  else if (status === 404) showMessage('Gist not found.');\n  else if (status >= 500) retry();\n  else throw err;\n}","preventionTips":["Authenticate to raise the rate limit and avoid 403s.","Heed the X-RateLimit-Remaining warning the code already logs near the limit.","Retry with backoff on 5xx; do not retry 404 (gist gone)."],"tags":["github-api","gist","network","rate-limit","http-status"],"backgroundTag":null,"analyzedSha":"9515cd4e58ebed69f78742d932b501c2cab8ad8f","analyzedAt":"2026-08-13T06:28:10.346Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}