decolua/9router · error · Error

MITM server failed to start. ${reason}

Error message

MITM server failed to start. ${reason}

What it means

After spawning the MITM server process, startServer polls its health endpoint for up to 8 seconds (pollMitmHealth(8000, MITM_PORT)). If the server never becomes healthy, it kills the spawned process and throws 'MITM server failed to start. <reason>'. The reason is startError if one was captured during spawn/boot, otherwise a hint to check sudo password or port 443, plus the owner of port 443 if one was detected.

Source

Thrown at src/mitm/manager.js:716

    });
    serverProcess.on("exit", (code) => {
      log(`Server exited (code: ${code})`);
      serverProcess = null;
      serverPid = null;
      try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
      try { fs.unlinkSync(LOCK_FILE); } catch { /* ignore */ }
      // Auto-restart on unexpected exit
      if (code !== 0 && !mitmIsRestarting) scheduleMitmRestart(apiKey);
    });
  }

  const health = await pollMitmHealth(8000, MITM_PORT);
  if (!health) {
    if (serverProcess && !serverProcess.killed) { try { serverProcess.kill(); } catch { /* ignore */ } serverProcess = null; }
    const processUsing443 = getProcessUsingPort443();
    const portInfo = processUsing443 ? ` Port 443 already in use by ${processUsing443}.` : "";
    const reason = startError || `Check sudo password or port 443 access.${portInfo}`;
    throw new Error(`MITM server failed to start. ${reason}`);
  }

  if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });

  log(`✅ Server healthy (PID: ${serverPid || health.pid})`);

  // Log DNS status per tool
  const dnsStatus = checkAllDNSStatus();
  for (const [tool, active] of Object.entries(dnsStatus)) {
    log(`🌐 DNS ${tool}: ${active ? "✅ active" : "❌ inactive"}`);
  }

  await saveMitmSettings(true, sudoPassword);
  if (sudoPassword) setCachedPassword(sudoPassword);

  // Server is healthy — remove lock file (PID file persists as the marker)
  try { fs.unlinkSync(LOCK_FILE); } catch { /* ignore */ }

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Read the reason suffix: if it names the port-443 owner, stop that service or retry with forceKillPort443=true (the start call's force flag / dashboard prompt 'kill and continue')
  2. Verify the sudo password is correct and re-save it — a bad password breaks privileged cleanup and the 443 bind on Linux/macOS
  3. Free port 443 manually (`sudo lsof -i :443` / `netstat -ano | findstr :443`) then retry; on Windows authorize the app to kill the owner
  4. Reproduce the child's boot error directly: run the runtime mitm server.js by hand from the MITM_DIR to see the real crash, fix it (reinstall if files are corrupt), and start again

Example fix

// before
await startServer(apiKey, maybeStalePassword);
// after: pre-check the port and pass a fresh password + force flag
const inUse = getProcessUsingPort443();
if (inUse) console.warn('port 443 held by', inUse);
await startServer(apiKey, await loadEncryptedPassword(), /* forceKillPort443 */ true);
Defensive patterns

Strategy: try-catch

Validate before calling

const { execSync } = require('child_process');
function port443Owner() {
  try {
    return execSync('lsof -ti :443', { encoding: 'utf-8' }).trim() || null; // win: netstat -ano | findstr :443
  } catch { return null; }
}
if (port443Owner()) throw new Error('Free port 443 (or pass forceKillPort443) before starting the MITM proxy.');

Try / catch

try {
  await startServer(apiKey, password, forceKill);
} catch (e) {
  if (/MITM server failed to start/.test(e.message)) {
    if (/port 443/i.test(e.message)) {
      await stopPort443Owner(); // stop nginx/IIS/Apache or pass forceKillPort443=true
    } else if (/sudo|password/i.test(e.message)) {
      await reSaveSudoPassword();
    }
    await startServer(apiKey, password, forceKill); // single retry after remediation
  } else throw e;
}

Prevention

When it happens

Trigger: Port 443 occupied by another process (web server, IIS, Apache, another proxy) that wasn't detected/killable; sudo password wrong so leftover-process cleanup or privileged bind failed; the server.js process crashed at boot (bad runtime files, missing Node runtime, config error); firewall/security software blocking the bind or the health probe; slow machine where 8s wasn't enough.

Common situations: Windows with IIS or `http.sys` bound to 443; Docker/nginx already on 443; wrong sudo password saved so the child couldn't bind port 443 without root; stale PID file pointing at a process that just died; corporate EDR killing the spawned mitm server.js immediately.

Related errors


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