vercel/next.js · error

Server process exited before becoming ready (is port already

Error message

Server process exited before becoming ready (is port already in use?)

What it means

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.

Source

Thrown at bench/render-pipeline/client-trace.ts:234

    throw new Error(
      `Command failed: ${command} ${args.join(' ')} (exit ${code})`
    )
  }
}

async function waitForServerReady(
  url: string,
  timeoutMs: number,
  serverDied?: () => boolean
): Promise<void> {
  const start = performance.now()
  while (performance.now() - start < timeoutMs) {
    // Without this check, a server that dies on startup (e.g. EADDRINUSE
    // against a stale server on the same port) is indistinguishable from
    // a slow one — worse, a 200 from whatever else owns the port would
    // pass, and the run would silently measure the wrong server.
    if (serverDied?.()) {
      throw new Error(
        `Server process exited before becoming ready (is port already in use?)`
      )
    }
    try {
      const response = await fetch(url, { cache: 'no-store' })
      await response.arrayBuffer()
      if (response.ok) return
    } catch {
      // server not ready yet
    }
    await sleep(200)
  }
  throw new Error(`Server did not become ready within ${timeoutMs}ms`)
}

// The death check alone is racy on a contested port: a stale server can
// answer the readiness probe before our child fails to bind, and the run
// would silently measure the wrong server.

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Free the port: find and kill the process (lsof -i :PORT then kill), or pass --port with a free value.
  2. Rebuild the fixture (pnpm --filter=next build) if next start is crashing on missing output.
  3. Run next start manually in the fixture dir to see the crash reason.
  4. Ensure no required environment variables are missing.

Example fix

# before: stale server holds the port
next start  # exits with EADDRINUSE

# after
lsof -ti:3199 | xargs kill; next start --port 3199
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the port is free before spawning the server
import net from 'node:net'
async function isPortFree(port: number): Promise<boolean> {
  return new Promise(resolve => {
    const tester = net.createServer()
    tester.once('error', () => resolve(false))
    tester.listen(port, () => tester.close(() => resolve(true)))
  })
}
if (!(await isPortFree(port))) {
  throw new Error(`Free port ${port} before starting (lsof -ti:${port} | xargs kill)`)
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/3c996673fb3e250c. Report an issue: GitHub.