GoogleChrome/lighthouse · error

Invalid API response: ${await response.text()}

Error message

Invalid API response: ${await response.text()}

What it means

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.

Source

Thrown at core/scripts/internal-analysis/download-issues.js:69

}

/**
 * @param {AugmentedGitHubIssue} issue
 */
async function fetchAndInjectEvents(issue) {
  process.stdout.write(`Fetching ${issue.events_url}...\n`);
  const response = await fetch(issue.events_url, {headers: HEADERS});
  const events = await response.json();
  issue.events = events;
}

/**
 * @param {AugmentedGitHubIssue} issue
 */
async function fetchAndInjectComments(issue) {
  process.stdout.write(`Fetching ${issue.comments_url}...\n`);
  const response = await fetch(issue.comments_url, {headers: HEADERS});
  if (!response.ok) throw new Error(`Invalid API response: ${await response.text()}`);
  const comments = await response.json();
  issue.comments = comments;
  if (!Array.isArray(issue.comments)) {
    console.warn('Comments was not an array', issue.comments);
    issue.comments = [];
  }

  if (issue.pull_request) {
    const prCommentsUrl = issue.comments_url
      .replace('/issues/', '/pulls/')
      .replace('/comments', '/reviews');
    process.stdout.write(`Fetching ${prCommentsUrl}...\n`);
    const response = await fetch(prCommentsUrl, {headers: HEADERS});
    if (!response.ok) throw new Error(`Invalid API response: ${await response.text()}`);
    const comments = await response.json();
    issue.comments = issue.comments.concat(comments);
  }
}

View on GitHub (pinned to 9515cd4e58)

Solutions

  1. Set a valid GITHUB_TOKEN with repo/public_repo read scope in the environment.
  2. If rate-limited (403 with X-RateLimit-Remaining: 0), wait and retry or reduce request volume.
  3. Verify the issue URL is correct and the repo exists.

Example fix

// before
const response = await fetch(issue.comments_url, {headers: HEADERS});
// after
if (!process.env.GITHUB_TOKEN) throw new Error('Set GITHUB_TOKEN');
const response = await fetch(issue.comments_url, {headers: HEADERS});
if (!response.ok) throw new Error(`Invalid API response: ${await response.text()}`);
Defensive patterns

Strategy: retry

Validate before calling

async function safeFetchJson(url, headers) {
  for (let attempt = 0; attempt < 3; attempt++) {
    const res = await fetch(url, {headers});
    if (res.status === 403 && res.headers.get('x-ratelimit-remaining') === '0') {
      const reset = Number(res.headers.get('x-ratelimit-reset')) * 1000;
      await new Promise(r => setTimeout(r, Math.max(0, reset - Date.now())));
      continue;
    }
    if (res.ok) return res.json();
    throw new Error(`Invalid API response: ${await res.text()}`);
  }
  throw new Error('rate limited after retries');
}

Try / catch

try {
  await fetchAndInjectComments(issue);
} catch (e) {
  if (/rate limit/i.test(e.message)) { /* back off and retry */ }
  else throw e;
}

Prevention

When it happens

Trigger: Calling download-issues when GitHub returns 401 (bad/missing token), 403 (rate limit or forbidden), or 404 (issue deleted/moved).

Common situations: Missing or expired GITHUB_TOKEN env var; hitting GitHub's secondary rate limits; the issue or repo has been deleted.

Related errors


AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13). Data as JSON: /api/errors/fff32eb6575ec3ec. Report an issue: GitHub.