vercel/next.js · error

Server did not become ready within ${timeoutMs}ms

Error message

Server did not become ready within ${timeoutMs}ms

What it means

Thrown by waitForServerReady (benchmark.ts:321) when the readiness loop exhausts timeoutMs (default 30000 via --timeout-ms) without the server returning response.ok, and crucially without the child having exited (that's error [14]). So the process is alive but never served a healthy 200 — it's hung in boot, slow to compile, or stuck returning non-2xx/non-5xx (e.g. endless redirects) that never satisfy response.ok.

Source

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

    // 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`)
}

function spawnedServerDied(server: ReturnType<typeof spawn>): () => boolean {
  return () => server.exitCode !== null || server.signalCode !== null
}

// 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 {

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Raise --timeout-ms if boot is legitimately slow (e.g. --timeout-ms=120000).
  2. Ensure the first route in --routes exists and returns 200 — the readiness probe uses routes[0] (benchmark.ts:766, 893).
  3. Check the server isn't stuck returning redirects/404s by curling the probe URL directly.
  4. Reproduce by running the server command manually and timing the first 200.

Example fix

# before — probe hits a missing first route, never 200s
#   pnpm bench:render-pipeline --routes=/nope,/dashboard

# after — first route exists, and bump the boot timeout if needed
#   pnpm bench:render-pipeline --routes=/dashboard,/blog --timeout-ms=60000
Defensive patterns

Strategy: validation

Validate before calling

// confirm the first route returns 200 before the long boot probe depends on it
async function firstRouteOk(base: string, firstRoute: string): Promise<boolean> {
  try {
    const res = await fetch(`${base}${firstRoute}`, { signal: AbortSignal.timeout(2000) })
    return res.ok
  } catch { return false }
}

Type guard

function isReadinessTimeout(err: unknown): boolean {
  return err instanceof Error && /Server did not become ready within/.test(err.message)
}

Try / catch

try {
  await waitForServerReady(url, timeoutMs, serverDied)
} catch (err) {
  if (isReadinessTimeout(err) && !isServerDiedError(err)) {
    console.error(`Server alive but never returned 200 within ${timeoutMs}ms. Probe URL: ${url}. Raise --timeout-ms or check the first route.`)
  }
  throw err
}

Prevention

When it happens

Trigger: The spawned server stays alive but never answers 2xx within --timeout-ms: extremely slow first compile/build output load, a server stuck in a boot loop that doesn't crash, returning 3xx/4xx forever, or a route that 404s on the probe URL (the probe hits the first route in routeSubset.routes, so a bad first route can keep failing).

Common situations: First route in --routes doesn't exist on the server (probe 404s indefinitely); very slow disk/CPU making boot exceed 30s; the server is up but misconfigured to never return 200 on the probe path.

Understand the failure class

Related errors


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