{"record":{"id":"3c996673fb3e250c","repo":"vercel/next.js","slug":"server-process-exited-before-becoming-ready-is-po-3c9966","errorCode":null,"errorMessage":"Server process exited before becoming ready (is port already in use?)","messagePattern":"Server process exited before becoming ready \\(is port already in use\\?\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"bench/render-pipeline/client-trace.ts","lineNumber":234,"sourceCode":"    throw new Error(\n      `Command failed: ${command} ${args.join(' ')} (exit ${code})`\n    )\n  }\n}\n\nasync function waitForServerReady(\n  url: string,\n  timeoutMs: number,\n  serverDied?: () => boolean\n): Promise<void> {\n  const start = performance.now()\n  while (performance.now() - start < timeoutMs) {\n    // Without this check, a server that dies on startup (e.g. EADDRINUSE\n    // against a stale server on the same port) is indistinguishable from\n    // a slow one — worse, a 200 from whatever else owns the port would\n    // pass, and the run would silently measure the wrong server.\n    if (serverDied?.()) {\n      throw new Error(\n        `Server process exited before becoming ready (is port already in use?)`\n      )\n    }\n    try {\n      const response = await fetch(url, { cache: 'no-store' })\n      await response.arrayBuffer()\n      if (response.ok) return\n    } catch {\n      // server not ready yet\n    }\n    await sleep(200)\n  }\n  throw new Error(`Server did not become ready within ${timeoutMs}ms`)\n}\n\n// The death check alone is racy on a contested port: a stale server can\n// answer the readiness probe before our child fails to bind, and the run\n// would silently measure the wrong server.","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/bench/render-pipeline/client-trace.ts#L216-L252","documentation":"Thrown by waitForServerReady when the spawned dev/start server process exits (serverDied() returns true) before the readiness probe ever succeeds. This distinguishes a dead server from a slow one and specifically guards against the contested-port race where a stale server answers the probe while the new child fails to bind (EADDRINUSE). Without it, the tracer would silently measure the wrong server.","triggerScenarios":"The server child crashes on startup; EADDRINUSE because another process owns the port; the build output is missing or corrupt so next start exits immediately; a required env var is unset causing an early fatal.","commonSituations":"A previous benchmark left a server running on the same port; switching branches without rebuilding so next start fails; missing NEXT_BIN or built artifacts.","solutions":["Free the port: find and kill the process (lsof -i :PORT then kill), or pass --port with a free value.","Rebuild the fixture (pnpm --filter=next build) if next start is crashing on missing output.","Run next start manually in the fixture dir to see the crash reason.","Ensure no required environment variables are missing."],"exampleFix":"# before: stale server holds the port\nnext start  # exits with EADDRINUSE\n\n# after\nlsof -ti:3199 | xargs kill; next start --port 3199","handlingStrategy":"validation","validationCode":"// Ensure the port is free before spawning the server\nimport net from 'node:net'\nasync function isPortFree(port: number): Promise<boolean> {\n  return new Promise(resolve => {\n    const tester = net.createServer()\n    tester.once('error', () => resolve(false))\n    tester.listen(port, () => tester.close(() => resolve(true)))\n  })\n}\nif (!(await isPortFree(port))) {\n  throw new Error(`Free port ${port} before starting (lsof -ti:${port} | xargs kill)`)\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Always free the port or pick a fresh one before each run.","Run next start manually in the fixture to catch startup crashes.","Rebuild after branch switches so next start has valid output."],"tags":["server","startup","port-conflict"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}