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
- Stop whatever is serving on the port (the message's instruction), then re-run.
- Pass a different --port to sidestep the conflict.
- Find the holder: lsof -i :{port} / ss -ltnp 'sport = :{port}' and kill it.
- 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
- Always pass a known-free --port, especially in CI where ports persist across jobs.
- Kill servers in finally blocks so crashed runs don't leave listeners.
- Never run two benchmark instances on the same port.
- lsof/ss the port quickly when this fires to find and stop the holder.
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
- Server process exited before becoming ready (is port already
- Server did not become ready within ${timeoutMs}ms
- Request failed (${response.status}) for ${url}
- [inspect] ${route}: not an App Router document (no __next_f)
- [${label}] warmup: all ${batchSize} requests failed — server
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/52a95b4acd392d52.
Report an issue: GitHub.