vercel/next.js · error

Port ${port} is already serving responses — another server i

Error message

Port ${port} is already serving responses — another server is running. Stop it or pass a different --port.

What it means

Thrown by assertPortFree (benchmark.ts:344) when a pre-flight probe to http://127.0.0.1:{port}/ succeeds (returns a response) before the benchmark spawns its own server. This is a deliberate guard against the contested-port race: if something is already answering on the port, spawning our server would either fail to bind or — worse — silently let the readiness probe hit the wrong server, corrupting measurements. assertPortFree is called at the start of each session (runMinimalServerSession, runE2EServerSession).

Source

Thrown at bench/render-pipeline/benchmark.ts:344

}

// 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.
async function assertPortFree(port: number): Promise<void> {
  const controller = new AbortController()
  const timeout = setTimeout(() => controller.abort(), 1000)
  try {
    await fetch(`http://127.0.0.1:${port}/`, {
      cache: 'no-store',
      signal: controller.signal,
    })
  } catch {
    return
  } finally {
    clearTimeout(timeout)
  }
  throw new Error(
    `Port ${port} is already serving responses — another server is running. ` +
      `Stop it or pass a different --port.`
  )
}

// Reads the body as a stream so TTFB (first body chunk) can be observed
// separately from total latency. Byte counts are of the decompressed body.
async function measureRequest(
  url: string,
  timeoutMs: number
): Promise<RequestSample> {
  const controller = new AbortController()
  const timeout = setTimeout(() => controller.abort(), timeoutMs)

  try {
    const start = performance.now()
    const response = await fetch(url, {
      cache: 'no-store',

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Stop whatever is serving on the port (the message's instruction), then re-run.
  2. Pass a different --port to sidestep the conflict.
  3. Find the holder: lsof -i :{port} / ss -ltnp 'sport = :{port}' and kill it.
  4. Ensure prior runs exit cleanly so they don't leak servers; avoid running two benchmarks on the same port.

Example fix

# before — stale server on 3199 trips the pre-flight check
#   pnpm bench:render-pipeline --port=3199
#   -> Port 3199 is already serving responses ...

# fix — use a free port (or stop the holder first)
#   pnpm bench:render-pipeline --port=3211
Defensive patterns

Strategy: validation

Validate before calling

import { createConnection } from 'node:net'
async function isPortServing(port: number): Promise<boolean> {
  return new Promise((resolveFn) => {
    const sock = createConnection({ port, host: '127.0.0.1' })
    sock.on('connect', () => { sock.destroy(); resolveFn(true) })
    sock.on('error', () => resolveFn(false))
  })
}
if (await isPortServing(port)) throw new Error(`Port ${port} is already in use; pick another via --port`)

Type guard

function isPortBusyError(err: unknown): boolean {
  return err instanceof Error && /already serving responses/.test(err.message)
}

Try / catch

// the guard fires before spawn; you usually surface and exit:
try {
  await assertPortFree(options.port)
} catch (err) {
  if (isPortBusyError(err)) {
    console.error((err as Error).message)
    console.error(`Find holder: lsof -i :${options.port}  (or: ss -ltnp 'sport = :${options.port}')`)
    process.exit(2)
  }
  throw err
}

Prevention

When it happens

Trigger: Any HTTP response comes back from 127.0.0.1:{port} within the 1s AbortController window before the benchmark starts its server: a leftover `next start`, another benchmark process, a dev server, or an unrelated service on that port. The probe treats any successful fetch (any status) as 'port is serving'.

Common situations: A previous benchmark run didn't clean up its server (crashed mid-run); user has their own dev server on 3199; port recycled from another tool; running two benchmark instances concurrently.

Related errors


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