{"record":{"id":"eb027a467ef4245e","repo":"vercel/next.js","slug":"request-failed-response-status-for-url","errorCode":null,"errorMessage":"Request failed (${response.status}) for ${url}","messagePattern":"Request failed \\((.+?)\\) for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"bench/render-pipeline/benchmark.ts","lineNumber":367,"sourceCode":"\n// Reads the body as a stream so TTFB (first body chunk) can be observed\n// separately from total latency. Byte counts are of the decompressed body.\nasync function measureRequest(\n  url: string,\n  timeoutMs: number\n): Promise<RequestSample> {\n  const controller = new AbortController()\n  const timeout = setTimeout(() => controller.abort(), timeoutMs)\n\n  try {\n    const start = performance.now()\n    const response = await fetch(url, {\n      cache: 'no-store',\n      signal: controller.signal,\n    })\n    if (!response.ok) {\n      await response.arrayBuffer().catch(() => undefined)\n      throw new Error(`Request failed (${response.status}) for ${url}`)\n    }\n    let ttfbMs = -1\n    if (response.body) {\n      const reader = response.body.getReader()\n      while (true) {\n        const { done } = await reader.read()\n        if (done) break\n        if (ttfbMs < 0) ttfbMs = performance.now() - start\n      }\n    }\n    const totalMs = performance.now() - start\n    if (ttfbMs < 0) ttfbMs = totalMs\n    return { totalMs, ttfbMs }\n  } finally {\n    clearTimeout(timeout)\n  }\n}\n","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/bench/render-pipeline/benchmark.ts#L349-L385","documentation":"Thrown by measureRequest (benchmark.ts:367) when a single measurement fetch returns a non-OK HTTP status. measureRequest is used in both warmup (via runSerialRequests) and the timed serial/under-load phases. In the timed phases this throw is caught locally (runSerialRequests/runConcurrentRequests count it as an error and continue), but in warmup's runSerialRequests a 100%-failure batch is later surfaced separately. The status is embedded so you can tell 500 from 404/429/etc.","triggerScenarios":"During measurement, the server returns 4xx/5xx for the benchmarked route: a route that doesn't exist (404), server error during load (500), rate limiting (429), or the server crashing under concurrency and returning errors. Each failed request throws this; the phase tallies them as errors and keeps going unless all fail.","commonSituations":"Benchmarking a route not present in the fixture (404); server throwing under high concurrency; the app has an unhandled error on that path; middleware returning 403; the server was measured against the wrong build.","solutions":["Check the post-run warnings: 'N/M requests failed' lines tell you how many; if all failed, the route is wrong or the server is broken.","curl the route URL directly to see the status and response body — fix the route or the app.","If failing only under load (--load-concurrency), reduce concurrency to see if it's a capacity/crash issue.","Confirm the build is current and the route exists in the fixture before benchmarking."],"exampleFix":"# before — benchmarking a non-existent route, all requests 404\n#   pnpm bench:render-pipeline --routes=/missing\n\n# after — benchmark a route the fixture actually serves\n#   curl -I http://127.0.0.1:3199/dashboard   # confirm 200 first\n#   pnpm bench:render-pipeline --routes=/dashboard","handlingStrategy":"try-catch","validationCode":"// before the timed phase, confirm the route is healthy:\nasync function routeIsHealthy(url: string): Promise<boolean> {\n  try {\n    const res = await fetch(url, { signal: AbortSignal.timeout(3000) })\n    return res.ok\n  } catch { return false }\n}\nif (!(await routeIsHealthy(measureUrl))) throw new Error(`pre-flight: ${measureUrl} not healthy`)","typeGuard":"function isRequestStatusError(err: unknown): boolean {\n  return err instanceof Error && /^Request failed \\(\\d{3}\\) for /.test(err.message)\n}","tryCatchPattern":"// In runSerialRequests/runConcurrentRequests this is ALREADY caught and counted as an error.\n// If you call measureRequest directly, mirror that tolerance:\ntry {\n  samples.push(await measureRequest(url, timeoutMs))\n} catch (err) {\n  if (isRequestStatusError(err)) { errors++; continue }\n  throw err\n}","preventionTips":["curl each route to confirm 200 before benchmarking.","Watch the 'N/M requests failed' warnings in the output — high error counts mean the route or server is broken, not a perf signal.","If errors appear only under --load-concurrency, reduce concurrency to isolate capacity vs correctness.","Ensure the build is current and routes exist in the fixture."],"tags":["http-status","request","measurement","render-pipeline","benchmark","load"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}