usebruno/bruno · error · Error
Unable to load custom CA certificate: ${(err as Error).messa
Error message
Unable to load custom CA certificate: ${(err as Error).message} What it means
getCACertificates fails to read an existing custom CA file. fs.existsSync returned true but fs.readFileSync threw (permissions, EISDIR, EACCES, encoding error), so the loader re-throws wrapped with the underlying message.
Source
Thrown at packages/bruno-requests/src/utils/ca-cert.ts:119
let systemCerts: string[] = [];
let rootCerts: string[] = [];
let customCerts: string[] = [];
let nodeExtraCerts: string[] = [];
// handle user-provided custom CA certificate file with optional default certificates
if (caCertFilePath) {
// validate custom CA certificate file
if (fs.existsSync(caCertFilePath)) {
try {
const customCert = fs.readFileSync(caCertFilePath, 'utf8');
if (customCert && customCert.trim()) {
customCerts.push(customCert);
caCertificatesCount.custom = customCerts.length;
}
} catch (err) {
console.error(`Failed to read custom CA certificate from ${caCertFilePath}:`, (err as Error).message);
throw new Error(`Unable to load custom CA certificate: ${(err as Error).message}`);
}
} else {
throw new Error(`Invalid custom CA certificate path: ${caCertFilePath}`);
}
if (shouldKeepDefaultCerts) {
// get system certs
systemCerts = getSystemCerts();
caCertificatesCount.system = systemCerts.length;
// get root certs
rootCerts = [...tls.rootCertificates];
caCertificatesCount.root = rootCerts.length;
}
} else {
// get system certs
systemCerts = getSystemCerts();
caCertificatesCount.system = systemCerts.length;View on GitHub (pinned to 9bdd81c7bd)
Solutions
- Confirm the path is a regular file: fs.statSync(caCertFilePath).isFile().
- Fix permissions (chmod 644 / take ownership) so the process can read it.
- Point caCertFilePath to a real .pem/.crt file rather than a directory.
Example fix
// before
{ caCertFilePath: '/etc/ssl/certs' } // directory -> EISDIR -> throws
// after
{ caCertFilePath: '/etc/ssl/certs/myCA.pem' } Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
function assertReadableCertFile(p) {
if (!p || !fs.existsSync(p)) throw new Error(`Invalid custom CA certificate path: ${p}`);
const st = fs.statSync(p);
if (!st.isFile()) throw new Error(`Unable to load custom CA certificate: not a file (${p})`);
fs.accessSync(p, fs.constants.R_OK);
} Type guard
function isReadableFile(p): p is string { try { return typeof p==='string' && !!p && fs.statSync(p).isFile() && fs.accessSync(p, fs.constants.R_OK) === undefined; } catch { return false; } } Try / catch
try { return getCACertificates({ caCertFilePath }); } catch (e) { if (/Unable to load custom CA certificate/.test(e.message)) { /* disable custom CA, retry with defaults */ } else throw e; } Prevention
- Stat the path to confirm it is a regular file before passing it in.
- Fix ownership/permissions on cert files used by the process.
When it happens
Trigger: caCertFilePath points to a directory or a special file, the process lacks read permission, the file was deleted between the existsSync and readFileSync calls (TOCTOU), or the file is not valid UTF-8.
Common situations: Path is a directory, a symlink to a non-readable target, on a network mount with intermittent access, or owned by root while bruno runs as a normal user.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Invalid custom CA certificate path: ${caCertFilePath}
- Failed to create default location
- Error reading cert/key file: ${err.message}
- Error reading pfx file: ${err.message}
- Failed to export ${environmentType} environments.
AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13).
Data as JSON: /api/errors/ddd21ce926ccf5ed.
Report an issue: GitHub.