remix-run/react-router · error

No available port found

Error message

No available port found

What it means

@react-router/serve's CLI resolves its listen port by probing the preferred port and then an ephemeral port (0). checkPort resolves undefined for EADDRINUSE and EACCES — skipping to the next candidate — and the fallback to port 0 normally always succeeds. 'No available port found' means even the ephemeral probe came back undefined, i.e. the process is denied socket binding outright (permission-denied on every attempt) in the current environment.

Solutions

  1. Relax the sandbox: run the container with default network capabilities instead of --cap-drop ALL style lockdown
  2. Check SELinux/AppArmor or firewall policy for socket-bind denials for the node process
  3. If you only meant to change interfaces, verify the --host value is an address this machine actually owns

Example fix

# before — binding denied by container lockdown
docker run --cap-drop ALL --network none my-app \
  npx react-router-serve ./build/server/index.js

# after — allow basic networking
docker run my-app \
  npx react-router-serve ./build/server/index.js
Defensive patterns

Strategy: retry

Validate before calling

// probe candidates (incl. ephemeral) before handing off to the server
import net from "node:net";
function probe(port: number, host?: string): Promise<number | undefined> {
  return new Promise((resolve) => {
    const s = net.createServer();
    s.once("error", () => resolve(undefined));
    s.listen(host ? { port, host } : { port }, () => {
      const addr = s.address();
      s.close(() => resolve(typeof addr === "object" && addr ? addr.port : undefined));
    });
  });
}
if ((await probe(0, host)) === undefined) {
  throw new Error("socket binding denied in this environment — fix sandbox/network policy");
}

Try / catch

// your own server bootstrap: walk candidate ports, treat denial separately
for (const port of [Number(process.env.PORT) || 3000, 3001, 0]) {
  try {
    await listen(port, host);
    break;
  } catch (err) {
    const code = (err as NodeJS.ErrnoException).code;
    if (code !== "EADDRINUSE") throw err; // EACCES/EADDRNOTAVAIL need a host/env fix, not a retry
  }
}

Prevention

When it happens

Trigger: Running react-router-serve in an environment where net.createServer().listen() fails with EACCES for both the preferred port and port 0 — e.g. a locked-down container/sandbox without network capabilities, or an OS policy denying socket creation.

Common situations: Hardened Docker/Kubernetes containers (network caps dropped), gVisor/Firecracker sandboxes, SELinux/AppArmor policies, CI runners with networking restricted, or non-root users denied socket ops.

Related errors


AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18). Data as JSON: /api/errors/5d01078cc1f87cba. Report an issue: GitHub.

Appendix: source

Thrown at packages/react-router-serve/cli.ts:80

  );
}

function parseNumber(raw?: string) {
  if (raw === undefined) return undefined;
  let maybe = Number(raw);
  if (Number.isNaN(maybe)) return undefined;
  return maybe;
}

async function getAvailablePort(
  preferredPort: number,
  host?: string,
): Promise<number> {
  let preferredAvailablePort = await checkPort(preferredPort, host);
  let availablePort = preferredAvailablePort ?? (await checkPort(0, host));

  if (availablePort === undefined) {
    throw new Error("No available port found");
  }

  return availablePort;
}

function checkPort(port: number, host?: string): Promise<number | undefined> {
  return new Promise((resolve, reject) => {
    let server = net.createServer();
    let listenOptions = host ? { port, host } : { port };

    server.unref();

    server.once("error", (error: NodeJS.ErrnoException) => {
      if (error.code === "EADDRINUSE" || error.code === "EACCES") {
        resolve(undefined);
      } else {
        reject(error);
      }

View on GitHub (pinned to 6beaca3952)