{"record":{"id":"206df2b57bdce030","repo":"GoogleChrome/lighthouse","slug":"unexpected-response-response-statuscode-resp","errorCode":null,"errorMessage":"unexpected response: ${response.statusCode} ${response.statusText}","messagePattern":"unexpected response: (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/scripts/lantern/collect/collect.js","lineNumber":143,"sourceCode":"    const responseJson = await fetchString(jsonUrl);\n    const response = JSON.parse(responseJson);\n\n    if (response.statusCode === 200) {\n      lhr = response.data.lighthouse;\n      assertLhr(lhr);\n      break;\n    }\n\n    if (response.statusCode >= 100 && response.statusCode < 200) {\n      // If behindCount doesn't exist, the test is currently running.\n      // * Wait 30 seconds if the test is currently running.\n      // * Wait an additional 10 seconds for every test ahead of this one.\n      // * Don't wait for more than 10 minutes.\n      const secondsToWait = Math.min(30 + 10 * (response.data.behindCount || 0), 10 * 1000);\n      if (DEBUG) log.log('poll wpt in', secondsToWait);\n      await new Promise((resolve) => setTimeout(resolve, secondsToWait * 1000));\n    } else {\n      throw new Error(`unexpected response: ${response.statusCode} ${response.statusText}`);\n    }\n  }\n\n  const traceUrl = new URL('/getgzip.php', WPT_URL);\n  traceUrl.searchParams.set('test', testId);\n  traceUrl.searchParams.set('file', 'lighthouse_trace.json');\n  const traceJson = await fetchString(traceUrl.href);\n\n  /** @type {LH.Trace} */\n  const trace = JSON.parse(traceJson);\n  // For some reason, the first trace event is an empty object.\n  trace.traceEvents = trace.traceEvents.filter(e => Object.keys(e).length > 0);\n\n  return {\n    lhr: JSON.stringify(lhr),\n    trace: JSON.stringify(trace),\n  };\n}","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/GoogleChrome/lighthouse/blob/9515cd4e58ebed69f78742d932b501c2cab8ad8f/core/scripts/lantern/collect/collect.js#L125-L161","documentation":"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.","triggerScenarios":"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.","commonSituations":"WPT API changes introducing new status codes; transient WPT server errors; test cancelled or invalidated server-side.","solutions":["Inspect the statusCode and statusText in the error to identify the unknown WPT state.","If transient, retry the collection after a wait.","If WPT changed its API, update the polling switch/case to handle the new status."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const EXPECTED_WPT_STATUSES = new Set([100, 101, 200, 400, 500]);\nfunction isExpectedWptPollStatus(statusCode) {\n  return EXPECTED_WPT_STATUSES.has(statusCode);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await pollTestUntilComplete(testId);\n} catch (e) {\n  if (/unexpected response/.test(e.message)) {\n    console.warn(`WPT polling returned unknown status, retrying: ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["Log the full WPT polling response when status codes are unexpected.","Retry transient WPT server errors before failing.","Update the polling state machine when WPT introduces new status codes."],"tags":["wpt","polling","api","lantern","state-machine"],"backgroundTag":null,"analyzedSha":"9515cd4e58ebed69f78742d932b501c2cab8ad8f","analyzedAt":"2026-08-13T06:28:10.346Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}