{"record":{"id":"fff32eb6575ec3ec","repo":"GoogleChrome/lighthouse","slug":"invalid-api-response-await-response-text","errorCode":null,"errorMessage":"Invalid API response: ${await response.text()}","messagePattern":"Invalid API response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/scripts/internal-analysis/download-issues.js","lineNumber":69,"sourceCode":"}\n\n/**\n * @param {AugmentedGitHubIssue} issue\n */\nasync function fetchAndInjectEvents(issue) {\n  process.stdout.write(`Fetching ${issue.events_url}...\\n`);\n  const response = await fetch(issue.events_url, {headers: HEADERS});\n  const events = await response.json();\n  issue.events = events;\n}\n\n/**\n * @param {AugmentedGitHubIssue} issue\n */\nasync function fetchAndInjectComments(issue) {\n  process.stdout.write(`Fetching ${issue.comments_url}...\\n`);\n  const response = await fetch(issue.comments_url, {headers: HEADERS});\n  if (!response.ok) throw new Error(`Invalid API response: ${await response.text()}`);\n  const comments = await response.json();\n  issue.comments = comments;\n  if (!Array.isArray(issue.comments)) {\n    console.warn('Comments was not an array', issue.comments);\n    issue.comments = [];\n  }\n\n  if (issue.pull_request) {\n    const prCommentsUrl = issue.comments_url\n      .replace('/issues/', '/pulls/')\n      .replace('/comments', '/reviews');\n    process.stdout.write(`Fetching ${prCommentsUrl}...\\n`);\n    const response = await fetch(prCommentsUrl, {headers: HEADERS});\n    if (!response.ok) throw new Error(`Invalid API response: ${await response.text()}`);\n    const comments = await response.json();\n    issue.comments = issue.comments.concat(comments);\n  }\n}","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/GoogleChrome/lighthouse/blob/9515cd4e58ebed69f78742d932b501c2cab8ad8f/core/scripts/internal-analysis/download-issues.js#L51-L87","documentation":"Thrown by fetchAndInjectComments() when the GitHub API response for an issue's comments URL is not ok (non-2xx). This is one of several identical guards in the issue-download script; this specific one fetches the main `/issues/{n}/comments` endpoint.","triggerScenarios":"Calling download-issues when GitHub returns 401 (bad/missing token), 403 (rate limit or forbidden), or 404 (issue deleted/moved).","commonSituations":"Missing or expired GITHUB_TOKEN env var; hitting GitHub's secondary rate limits; the issue or repo has been deleted.","solutions":["Set a valid GITHUB_TOKEN with repo/public_repo read scope in the environment.","If rate-limited (403 with X-RateLimit-Remaining: 0), wait and retry or reduce request volume.","Verify the issue URL is correct and the repo exists."],"exampleFix":"// before\nconst response = await fetch(issue.comments_url, {headers: HEADERS});\n// after\nif (!process.env.GITHUB_TOKEN) throw new Error('Set GITHUB_TOKEN');\nconst response = await fetch(issue.comments_url, {headers: HEADERS});\nif (!response.ok) throw new Error(`Invalid API response: ${await response.text()}`);","handlingStrategy":"retry","validationCode":"async function safeFetchJson(url, headers) {\n  for (let attempt = 0; attempt < 3; attempt++) {\n    const res = await fetch(url, {headers});\n    if (res.status === 403 && res.headers.get('x-ratelimit-remaining') === '0') {\n      const reset = Number(res.headers.get('x-ratelimit-reset')) * 1000;\n      await new Promise(r => setTimeout(r, Math.max(0, reset - Date.now())));\n      continue;\n    }\n    if (res.ok) return res.json();\n    throw new Error(`Invalid API response: ${await res.text()}`);\n  }\n  throw new Error('rate limited after retries');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await fetchAndInjectComments(issue);\n} catch (e) {\n  if (/rate limit/i.test(e.message)) { /* back off and retry */ }\n  else throw e;\n}","preventionTips":["Always set GITHUB_TOKEN before running download-issues.","Check rate limit status before bulk-fetching.","Handle 403 with X-RateLimit-Remaining: 0 by sleeping until reset."],"tags":["github-api","network","rate-limit","auth","download-issues"],"backgroundTag":null,"analyzedSha":"9515cd4e58ebed69f78742d932b501c2cab8ad8f","analyzedAt":"2026-08-13T06:28:10.346Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}