decolua/9router · error · Error

Root CA not found. Start server first to generate it.

Error message

Root CA not found. Start server first to generate it.

What it means

trustCert() installs the MITM root CA into the OS trust store, but the CA certificate is only generated when the MITM server starts. If MITM_DIR/rootCA.crt does not exist on disk, the function throws instead of installing a missing file. This forces the one-time server start that generates the certificate.

Source

Thrown at src/mitm/manager.js:848

  return { success: true };
}

/**
 * Disable DNS for a specific tool
 */
async function disableToolDNS(tool, sudoPassword) {
  const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
  await removeDNSEntry(tool, password);
  await saveDnsToolState(tool, false);
  return { success: true };
}

/**
 * Install Root CA to system trust store (standalone, no server start)
 */
async function trustCert(sudoPassword) {
  const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
  if (!fs.existsSync(rootCACertPath)) throw new Error("Root CA not found. Start server first to generate it.");
  const { installCert } = require("./cert/install");
  if (!IS_WIN && !IS_MAC && !isSudoAvailable()) {
    log(`🔐 Cert: system trust unavailable (no sudo). Use file: ${rootCACertPath}`);
    return;
  }
  const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
  if (!password && isSudoPasswordRequired()) throw new Error("Sudo password required to trust certificate");
  await installCert(password, rootCACertPath);
  if (password) setCachedPassword(password);
}

// Legacy aliases for backward compatibility
const startMitm = startServer;
const stopMitm = stopServer;

module.exports = {
  getMitmStatus,
  startServer,

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Start the MITM server once (await startServer()) so rootCA.crt is generated in MITM_DIR
  2. Verify the file exists: fs.existsSync(path.join(MITM_DIR, 'rootCA.crt'))
  3. If MITM_DIR was wiped or moved, restart the server to regenerate the CA, then re-trust
  4. On Linux without sudo, skip trustCert and manually trust the file printed in the log message

Example fix

// before
await trustCert(password);
// after
if (!fs.existsSync(path.join(MITM_DIR, "rootCA.crt"))) {
  await startServer({ sudoPassword: password }); // generates rootCA.crt
  await stopServer();
}
await trustCert(password);
Defensive patterns

Strategy: validation

Validate before calling

import fs from "fs";
if (!fs.existsSync(path.join(MITM_DIR, "rootCA.crt"))) {
  await startServer({}); // generates the CA
}
await trustCert(sudoPassword);

Type guard

function hasRootCA(p) { return typeof p === "string" && fs.existsSync(p); }

Try / catch

try {
  await trustCert(sudoPassword);
} catch (err) {
  if (err.message.includes("Root CA not found")) {
    await startServer({});
    await trustCert(sudoPassword);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling trustCert() on a machine where the MITM server has never been started, after manually deleting the MITM_DIR directory, or pointing the app at a fresh DATA_DIR/home directory.

Common situations: First-run setup where the user clicks 'Trust certificate' before ever starting the proxy; CI/container images with a wiped home dir; switching users so ~/.9router (or equivalent MITM_DIR) no longer holds rootCA.crt.

Related errors


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