GoogleChrome/lighthouse · error

unexpected response

Error message

unexpected response: ${response.statusCode} ${response.statusText}

What it means

Thrown inside the WPT test-polling loop when the response statusCode falls outside the expected set (1xx running, and the success/completion codes handled above). This catches any WPT polling response that isn't recognized as 'running', 'complete', or 'error', indicating an unexpected WPT state.

Solutions

  1. Inspect the statusCode and statusText in the error to identify the unknown WPT state.
  2. If transient, retry the collection after a wait.
  3. If WPT changed its API, update the polling switch/case to handle the new status.
Defensive patterns

Strategy: try-catch

Validate before calling

const EXPECTED_WPT_STATUSES = new Set([100, 101, 200, 400, 500]);
function isExpectedWptPollStatus(statusCode) {
  return EXPECTED_WPT_STATUSES.has(statusCode);
}

Try / catch

try {
  await pollTestUntilComplete(testId);
} catch (e) {
  if (/unexpected response/.test(e.message)) {
    console.warn(`WPT polling returned unknown status, retrying: ${e.message}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: WPT returns a polling response with an unexpected statusCode (e.g. a new status type, or a server error mid-test) that the polling logic doesn't have a branch for.

Common situations: WPT API changes introducing new status codes; transient WPT server errors; test cancelled or invalidated server-side.

Related errors


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

Appendix: source

Thrown at core/scripts/lantern/collect/collect.js:143

    const responseJson = await fetchString(jsonUrl);
    const response = JSON.parse(responseJson);

    if (response.statusCode === 200) {
      lhr = response.data.lighthouse;
      assertLhr(lhr);
      break;
    }

    if (response.statusCode >= 100 && response.statusCode < 200) {
      // If behindCount doesn't exist, the test is currently running.
      // * Wait 30 seconds if the test is currently running.
      // * Wait an additional 10 seconds for every test ahead of this one.
      // * Don't wait for more than 10 minutes.
      const secondsToWait = Math.min(30 + 10 * (response.data.behindCount || 0), 10 * 1000);
      if (DEBUG) log.log('poll wpt in', secondsToWait);
      await new Promise((resolve) => setTimeout(resolve, secondsToWait * 1000));
    } else {
      throw new Error(`unexpected response: ${response.statusCode} ${response.statusText}`);
    }
  }

  const traceUrl = new URL('/getgzip.php', WPT_URL);
  traceUrl.searchParams.set('test', testId);
  traceUrl.searchParams.set('file', 'lighthouse_trace.json');
  const traceJson = await fetchString(traceUrl.href);

  /** @type {LH.Trace} */
  const trace = JSON.parse(traceJson);
  // For some reason, the first trace event is an empty object.
  trace.traceEvents = trace.traceEvents.filter(e => Object.keys(e).length > 0);

  return {
    lhr: JSON.stringify(lhr),
    trace: JSON.stringify(trace),
  };
}

View on GitHub (pinned to 9515cd4e58)