decolua/9router · error

EADDRINUSE

EADDRINUSE

Error message

Port ${LOCAL_PORT} already in use

What it means

The MITM proxy server fails to bind its local listening port because another socket already holds it (errno EADDRINUSE). The server logs 'Port <LOCAL_PORT> already in use' and exits with code 1.

Source

Thrown at src/mitm/server.js:385

      }
    });
    log(`Killed ${pidList.length} process(es) on port ${port}`);
  } catch (e) {
    if (e.status !== 1) throw e;
  }
}

try {
  killPort(LOCAL_PORT);
} catch (e) {
  err(`Cannot kill process on port ${LOCAL_PORT}: ${e.message}`);
  process.exit(1);
}

server.listen(LOCAL_PORT, () => log(`🚀 Server ready on :${LOCAL_PORT}`));

server.on("error", (e) => {
  if (e.code === "EADDRINUSE") err(`Port ${LOCAL_PORT} already in use`);
  else if (e.code === "EACCES") err(`Permission denied for port ${LOCAL_PORT}`);
  else err(e.message);
  process.exit(1);
});

const { removeAllDNSEntriesSync } = require("./dns/dnsConfig");
let isShuttingDown = false;
const shutdown = () => {
  if (isShuttingDown) return;
  isShuttingDown = true;
  // Strip tool hosts from /etc/hosts so other apps aren't broken after exit
  removeAllDNSEntriesSync();
  const forceExit = setTimeout(() => process.exit(0), 1500);
  server.close(() => { clearTimeout(forceExit); process.exit(0); });
};
process.on("SIGTERM", shutdown);
process.on("SIGINT", shutdown);
if (process.platform === "win32") process.on("SIGBREAK", shutdown);

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Find and stop the process holding the port: lsof -i :<LOCAL_PORT> (or netstat) and kill the stale instance.
  2. Restart the tray/launcher which automatically kills processes LISTENING on LOCAL_PORT before starting.
  3. Change LOCAL_PORT (env/config) to a free port if the collision is with another service.
  4. Wait a moment and retry — TIME_WAIT sockets usually clear within a minute.

Example fix

// before
PORT=20128 (same as gateway) → EADDRINUSE
// after
MITM_LOCAL_PORT=20129 npm run start  # distinct from gateway port
Defensive patterns

Strategy: validation

Validate before calling

const net = require('net');
const port = Number(process.env.MITM_LOCAL_PORT || LOCAL_PORT);
const probe = net.createServer().once('error', (e) => {
  if (e.code === 'EADDRINUSE') console.error(`Port ${port} in use — pick another or stop the other instance`);
});
probe.listen(port, () => probe.close(() => startServer(port)));

Try / catch

server.on('error', (e) => {
  if (e.code === 'EADDRINUSE') {
    err(`Port ${LOCAL_PORT} already in use`);
    // optionally retry once after killing stale listeners on LOCAL_PORT
    process.exit(1);
  }
});

Prevention

When it happens

Trigger: server.listen(LOCAL_PORT) while another 9Router MITM instance, the gateway itself, or any unrelated process is already bound to the same local port.

Common situations: Two MITM instances launched (e.g. tray + manual); previous instance not fully shut down (lingering listener, the code even kills LISTENING processes on LOCAL_PORT for this reason); LOCAL_PORT collides with the gateway port 20128 or another dev server.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/a02d2fcd20eba62d. Report an issue: GitHub.