{"record":{"id":"51944abac7e7d257","repo":"GoogleChrome/lighthouse","slug":"unexpected-status-code-wptresponse-statuscode","errorCode":null,"errorMessage":"unexpected status code ${wptResponse.statusCode} ${wptResponse.statusText}","messagePattern":"unexpected status code (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/scripts/lantern/collect/collect.js","lineNumber":77,"sourceCode":"  const apiUrl = new URL('/runtest.php', WPT_URL);\n  apiUrl.search = new URLSearchParams({\n    k: WPT_KEY,\n    f: 'json',\n    url,\n    location: 'gce-us-east4-linux:Chrome.3GFast',\n    runs: '1',\n    lighthouse: '1',\n    mobile: '1',\n    // Make the trace file available over /getgzip.php.\n    lighthouseTrace: '1',\n    lighthouseScreenshots: '1',\n    // Disable some things that WPT does, such as a \"repeat view\" analysis.\n    type: 'lighthouse',\n  }).toString();\n  const wptResponseJson = await fetchString(apiUrl.href);\n  const wptResponse = JSON.parse(wptResponseJson);\n  if (wptResponse.statusCode !== 200) {\n    throw new Error(`unexpected status code ${wptResponse.statusCode} ${wptResponse.statusText}`);\n  }\n\n  return {\n    testId: wptResponse.data.testId,\n    jsonUrl: wptResponse.data.jsonUrl,\n  };\n}\n\n/**\n * @param {string} url\n * @return {Promise<Result>}\n */\nasync function runUnthrottledLocally(url) {\n  const artifactsFolder = `${LH_ROOT}/.tmp/collect-traces-artifacts`;\n  const {stdout} = await execFileAsync('node', [\n    `${LH_ROOT}/cli`,\n    url,\n    '--throttling-method=provided',","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/GoogleChrome/lighthouse/blob/9515cd4e58ebed69f78742d932b501c2cab8ad8f/core/scripts/lantern/collect/collect.js#L59-L95","documentation":"Thrown by startWptTest() after parsing the WPT API JSON response when `statusCode` is not 200. WPT wraps its own status inside the JSON body (separate from HTTP status), so this fires when WPT itself rejects the test request — e.g. invalid key, quota exceeded, or bad parameters.","triggerScenarios":"Calling the WPT `/runtest.php` endpoint with an invalid/expired WPT_KEY, exceeded test quota, unsupported location, or malformed test parameters.","commonSituations":"Expired WPT key; daily/monthly test quota exhausted; WPT location string changed; parameter format changed in a WPT API update.","solutions":["Check the wptResponse.statusText and statusCode in the error for WPT's specific rejection reason.","Verify WPT_KEY is valid and has remaining quota at webpagetest.org.","Confirm the location string (`gce-us-east4-linux:Chrome.3GFast`) and other params are still supported by the current WPT API."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function assertWptStatus(wptResponse) {\n  if (wptResponse.statusCode !== 200) {\n    throw new Error(`WPT rejected test: ${wptResponse.statusCode} ${wptResponse.statusText}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await startWptTest(url);\n} catch (e) {\n  if (/unexpected status code/.test(e.message)) {\n    console.error(`WPT test start failed: ${e.message}. Check WPT_KEY and quota.`);\n  }\n  throw e;\n}","preventionTips":["Verify WPT_KEY is valid and has quota before starting tests.","Check WPT statusText for specific rejection reasons.","Keep the location string and parameters in sync with the current WPT API."],"tags":["wpt","api","quota","config","lantern"],"backgroundTag":null,"analyzedSha":"9515cd4e58ebed69f78742d932b501c2cab8ad8f","analyzedAt":"2026-08-13T06:28:10.346Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}