decolua/9router · error · Error
Failed to trust certificate: ${e.message}
Error message
Failed to trust certificate: ${e.message} What it means
This wraps any failure from installCert(password, rootCACertPath) — the platform-specific routine that adds the 9Router Root CA to the OS trust store (security/updates settings on macOS, certutil/registry on Windows, update-ca-certificates equivalents on Linux). The original error message is preserved in the template so the root cause (command missing, permission denied, timeout, keychain rejection) surfaces as 'Failed to trust certificate: <cause>'.
Source
Thrown at src/mitm/manager.js:567
// Step 1.5: Auto-install Root CA if not trusted yet
const { checkCertInstalled } = require("./cert/install");
const rootCATrusted = await checkCertInstalled(rootCACertPath);
const linuxNoSystemTrust = !IS_WIN && !IS_MAC && !isSudoAvailable();
if (!rootCATrusted) {
log("🔐 Cert: not trusted → installing...");
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
if (linuxNoSystemTrust) {
log(`🔐 Cert: skipping system trust (no sudo). Install ${rootCACertPath} as a trusted CA on machines that use this proxy.`);
} else {
if (!password && isSudoPasswordRequired()) {
throw new Error("Sudo password required to install Root CA certificate");
}
try {
await installCert(password, rootCACertPath);
log("🔐 Cert: ✅ trusted");
} catch (e) {
throw new Error(`Failed to trust certificate: ${e.message}`);
}
}
} else {
log("🔐 Cert: already trusted ✅");
}
// Step 2: Spawn server (Root CA already installed in Step 1.5)
// Verify server.js exists — recopy if runtime file was deleted (antivirus/cleanup)
let effectiveServerPath = SERVER_PATH;
if (!effectiveServerPath || !fs.existsSync(effectiveServerPath)) {
log(`[MITM] server.js missing at ${effectiveServerPath} → recopying`);
effectiveServerPath = ensureRuntimeServer(resolveBundledServerPath());
if (!effectiveServerPath || !fs.existsSync(effectiveServerPath)) {
throw new Error(`MITM server.js not found at ${effectiveServerPath}. Reinstall 9router.`);
}
}
const mitmRouterBase = await resolveMitmRouterBaseUrl();
log(`🚀 Starting server... (router: ${mitmRouterBase})`);View on GitHub (pinned to 90b52e06ff)
Solutions
- Read the underlying cause in the message and fix accordingly (wrong password → re-save it; missing binary → install the ca-certificates package)
- Manually trust the CA: `sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ~/.9router/mitm/rootCA.crt` (macOS) or `sudo cp rootCA.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates` (Debian/Ubuntu), then restart — checkCertInstalled will skip install
- Regenerate the CA if the file is corrupt/expired: delete rootCA.crt/rootCA.key under the MITM_DIR so startServer regenerates them
- Use the linuxNoSystemTrust mode (run without sudo availability on Linux) and distribute the CA to client machines yourself
Example fix
// before: opaque failure at runtime
await startServer(apiKey, password);
// after: pre-trust manually so installCert is skipped
execSync(`sudo cp ${mitmDir}/rootCA.crt /usr/local/share/ca-certificates/9router.crt && sudo update-ca-certificates`);
await startServer(apiKey); Defensive patterns
Strategy: fallback
Validate before calling
const fs = require('fs');
const certPath = require('os').homedir() + '/.9router/mitm/rootCA.crt';
function caFilesLookValid() {
try {
const pem = fs.readFileSync(certPath, 'utf-8');
return pem.includes('BEGIN CERTIFICATE') && pem.includes('END CERTIFICATE');
} catch { return false; }
} Try / catch
try {
await startServer(apiKey, password);
} catch (e) {
const m = /Failed to trust certificate: (.+)/.exec(e.message);
if (m) {
console.error('CA install failed:', m[1]);
// fallback: install the CA manually with the platform tool, then retry
execSync(`sudo cp ${certPath} /usr/local/share/ca-certificates/9router.crt && sudo update-ca-certificates`);
await startServer(apiKey, password);
} else throw e;
} Prevention
- Keep certutil/security/update-ca-certificates installed on minimal images
- Regenerate the CA if rootCA.crt/key are truncated or expired rather than retrying installs over a bad file
- Re-save the encrypted sudo password after any OS password change
- On managed macOS, pre-approve the CA via MDM so keychain programmatic adds succeed
When it happens
Trigger: installCert's underlying command fails: sudo password wrong/expired, certutil/security/update-ca-trust binary missing or non-PATH, keychain denies the add, Linux without the expected CA directory, or the CA file is corrupt/just regenerated mid-flight.
Common situations: Wrong sudo password saved in the encrypted store (message like 'incorrect password attempts'); minimal Docker/CI image lacking certutil or update-ca-certificates; corporate-managed macOS where the keychain blocks adding root CAs programmatically; rootCA.crt truncated or expired after an interrupted generateCert; SELinux/AppArmor blocking writes to the system CA dir.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Sudo password required to install Root CA certificate
- Sudo password required to trust certificate
- User canceled authorization | Certificate install failed
- Certificate install failed: ${error.message}
- Root CA not found. Start server first to generate it.
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/295d17c5bcca9a28.
Report an issue: GitHub.