nestjs/nest · error · Error

Server did not become ready in ${timeoutMs}ms: ${url}

Error message

Server did not become ready in ${timeoutMs}ms: ${url}

What it means

An internal readiness guard in the benchmarks CLI (tools/benchmarks/src/main.ts:137). runOne forks a framework server (express/fastify/nest-express/nest-fastify) as a child process, then waitForServer polls the target URL with global fetch every 100ms; if it never returns 200 or 404 within timeoutMs (default 5000), it throws a plain Error with this message, aborting the whole benchmark run. Because the child is forked with stdio:'ignore', the underlying startup error is hidden — the timeout is the only symptom.

Source

Thrown at tools/benchmarks/src/main.ts:137

  const hasFetch = typeof (globalThis as any).fetch === 'function';

  while (Date.now() - start < timeoutMs) {
    try {
      if (hasFetch) {
        const res = await (globalThis as any).fetch(url, { method: 'GET' });
        if (res && (res.status === 200 || res.status === 404)) return;
      } else {
        // best-effort fallback
        await sleep(250);
        return;
      }
    } catch {
      // server not ready yet
    }
    await sleep(100);
  }

  throw new Error(`Server did not become ready in ${timeoutMs}ms: ${url}`);
}

function killChild(child: ChildProcess): void {
  if (!child || child.killed) return;

  // Try graceful termination first.
  try {
    child.kill('SIGTERM');
  } catch {
    // ignore
  }

  // Force kill if still alive shortly after.
  setTimeout(() => {
    try {
      if (!child.killed) child.kill('SIGKILL');
    } catch {
      // ignore

View on GitHub (pinned to 6ec0e2783d)

Solutions

  1. Free port 3000 (lsof/iOSTAT or pick --port) before running the benchmark.
  2. Build the framework bundles first so fork() resolves a real entry file.
  3. Temporarily change stdio from 'ignore' to 'inherit' to see the child's startup error.
  4. Raise the timeout (waitForServer(url, 15_000)) on slow machines, and surface child stderr in the thrown message.

Example fix

// before
const child = fork(frameworkEntry(framework), { stdio: 'ignore' });
...
throw new Error(`Server did not become ready in ${timeoutMs}ms: ${url}`);

// after
const child = fork(frameworkEntry(framework), { stdio: 'inherit' });
child.stderr?.on('data', d => console.error(`[${framework}]`, d.toString()));
await waitForServer(url, 15_000);
Defensive patterns

Strategy: retry

Validate before calling

// Before running, ensure the port is free and the bundle is built.
import { createServer } from 'node:net';

async function isPortFree(port: number): Promise<boolean> {
  return new Promise(resolve => {
    const tester = createServer();
    tester.once('error', () => resolve(false));
    tester.once('listening', () => tester.close(() => resolve(true)));
    tester.listen(port);
  });
}

if (!(await isPortFree(args.port))) {
  throw new Error(`port ${args.port} is already in use`);
}

Type guard

function isChildError(e: unknown, codes: string[]): boolean {
  return typeof e === 'object' && e !== null
    && codes.includes((e as NodeJS.ErrnoException).code ?? '');
}

Try / catch

try {
  await runOne(framework, args);
} catch (e) {
  if (e instanceof Error && /did not become ready/.test(e.message)) {
    // inspect child stderr (switch stdio to 'inherit'), free the port, or raise timeout
    console.error('startup failed — re-run with stdio: inherit');
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `npm run benchmarks` when the forked framework process crashes on boot, binds the wrong port, or never listens — e.g., port 3000 already in use, missing compiled bundle at the forked entry path, framework built for an incompatible Node version, or a slow CI box exceeding the 5s budget.

Common situations: Another dev server already occupying :3000; dist/ not built (node resolves a path with no compiled JS); framework entry file path changed after a refactor; child crashes synchronously on import but stdio:'ignore' swallows it; CI runner under load.


AI-assisted analysis of nestjs/nest@6ec0e2783d (2026-08-03). Data as JSON: /data/errors/027cd31ca72c4181.json. Report an issue: GitHub.