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
- Start the MITM server once (await startServer()) so rootCA.crt is generated in MITM_DIR
- Verify the file exists: fs.existsSync(path.join(MITM_DIR, 'rootCA.crt'))
- If MITM_DIR was wiped or moved, restart the server to regenerate the CA, then re-trust
- 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
- Run the MITM server at least once before offering the 'trust certificate' action
- Disable/grey out the trust button in the UI until rootCA.crt exists
- Guard against wiping MITM_DIR; back up rootCA.crt across reinstalls
- In containers/CI, mount or pre-generate the CA as part of setup
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
- Certificate file not found: ${certPath}
- MITM server is already starting (lock contention)
- Sudo password required to install Root CA certificate
- Failed to trust certificate: ${e.message}
- MITM server.js not found at ${effectiveServerPath}. Reinstal
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/b39ce967322ca444.
Report an issue: GitHub.