{"record":{"id":"4361ea9bc9ab81d4","repo":"decolua/9router","slug":"mitm-server-failed-to-start-reason","errorCode":null,"errorMessage":"MITM server failed to start. ${reason}","messagePattern":"MITM server failed to start\\. (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mitm/manager.js","lineNumber":716,"sourceCode":"    });\n    serverProcess.on(\"exit\", (code) => {\n      log(`Server exited (code: ${code})`);\n      serverProcess = null;\n      serverPid = null;\n      try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }\n      try { fs.unlinkSync(LOCK_FILE); } catch { /* ignore */ }\n      // Auto-restart on unexpected exit\n      if (code !== 0 && !mitmIsRestarting) scheduleMitmRestart(apiKey);\n    });\n  }\n\n  const health = await pollMitmHealth(8000, MITM_PORT);\n  if (!health) {\n    if (serverProcess && !serverProcess.killed) { try { serverProcess.kill(); } catch { /* ignore */ } serverProcess = null; }\n    const processUsing443 = getProcessUsingPort443();\n    const portInfo = processUsing443 ? ` Port 443 already in use by ${processUsing443}.` : \"\";\n    const reason = startError || `Check sudo password or port 443 access.${portInfo}`;\n    throw new Error(`MITM server failed to start. ${reason}`);\n  }\n\n  if (_updateSettings) await _updateSettings({ mitmCertInstalled: true }).catch(() => { });\n\n  log(`✅ Server healthy (PID: ${serverPid || health.pid})`);\n\n  // Log DNS status per tool\n  const dnsStatus = checkAllDNSStatus();\n  for (const [tool, active] of Object.entries(dnsStatus)) {\n    log(`🌐 DNS ${tool}: ${active ? \"✅ active\" : \"❌ inactive\"}`);\n  }\n\n  await saveMitmSettings(true, sudoPassword);\n  if (sudoPassword) setCachedPassword(sudoPassword);\n\n  // Server is healthy — remove lock file (PID file persists as the marker)\n  try { fs.unlinkSync(LOCK_FILE); } catch { /* ignore */ }\n","sourceCodeStart":698,"sourceCodeEnd":734,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/mitm/manager.js#L698-L734","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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')","Verify the sudo password is correct and re-save it — a bad password breaks privileged cleanup and the 443 bind on Linux/macOS","Free port 443 manually (`sudo lsof -i :443` / `netstat -ano | findstr :443`) then retry; on Windows authorize the app to kill the owner","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"],"exampleFix":"// before\nawait startServer(apiKey, maybeStalePassword);\n// after: pre-check the port and pass a fresh password + force flag\nconst inUse = getProcessUsingPort443();\nif (inUse) console.warn('port 443 held by', inUse);\nawait startServer(apiKey, await loadEncryptedPassword(), /* forceKillPort443 */ true);","handlingStrategy":"try-catch","validationCode":"const { execSync } = require('child_process');\nfunction port443Owner() {\n  try {\n    return execSync('lsof -ti :443', { encoding: 'utf-8' }).trim() || null; // win: netstat -ano | findstr :443\n  } catch { return null; }\n}\nif (port443Owner()) throw new Error('Free port 443 (or pass forceKillPort443) before starting the MITM proxy.');","typeGuard":null,"tryCatchPattern":"try {\n  await startServer(apiKey, password, forceKill);\n} catch (e) {\n  if (/MITM server failed to start/.test(e.message)) {\n    if (/port 443/i.test(e.message)) {\n      await stopPort443Owner(); // stop nginx/IIS/Apache or pass forceKillPort443=true\n    } else if (/sudo|password/i.test(e.message)) {\n      await reSaveSudoPassword();\n    }\n    await startServer(apiKey, password, forceKill); // single retry after remediation\n  } else throw e;\n}","preventionTips":["Reserve port 443 for 9Router — disable/stop IIS, Apache, nginx, or other HTTPS proxies on the same host","Keep a valid saved sudo password; a bad password is a top cause of privileged-bind failure","After a failed start, run the runtime mitm server.js manually to see the child's real boot error","Increase tolerance on slow machines by remediating port conflicts before start rather than racing the 8s health window"],"tags":["startup","port-conflict","timeout","health-check","mitm"],"backgroundTag":"mitm-server-start-failed","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}