usebruno/bruno · error · Error

Error reading cert/key file

Error message

Error reading cert/key file

What it means

While building the HTTPS agent for a client-certificate request, Bruno interpolates certFilePath/keyFilePath, resolves them (absolute or relative to the collection), and `fs.readFileSync`s both. Any failure - ENOENT, EACCES, EISDIR, or interpolation producing a non-string - is caught and re-thrown as 'Error reading cert/key file' plus the appended original err.

Source

Thrown at packages/bruno-electron/src/ipc/network/cert-utils.js:95

    const domain = interpolateString(clientCert?.domain, interpolationOptions);
    const type = clientCert?.type || 'cert';
    if (domain) {
      const hostRegex = '^(https:\\/\\/|grpc:\\/\\/|grpcs:\\/\\/|ws:\\/\\/|wss:\\/\\/)?'
        + domain.replaceAll('.', '\\.').replaceAll('*', '.*');
      const requestUrl = interpolateString(request.url, interpolationOptions);
      if (requestUrl && requestUrl.match(hostRegex)) {
        if (type === 'cert') {
          try {
            let certFilePath = interpolateString(clientCert?.certFilePath, interpolationOptions);
            certFilePath = path.isAbsolute(certFilePath) ? certFilePath : path.join(collectionPath, certFilePath);
            let keyFilePath = interpolateString(clientCert?.keyFilePath, interpolationOptions);
            keyFilePath = path.isAbsolute(keyFilePath) ? keyFilePath : path.join(collectionPath, keyFilePath);

            httpsAgentRequestFields['cert'] = fs.readFileSync(certFilePath);
            httpsAgentRequestFields['key'] = fs.readFileSync(keyFilePath);
          } catch (err) {
            console.error('Error reading cert/key file', err);
            throw new Error('Error reading cert/key file' + err);
          }
        } else if (type === 'pfx') {
          try {
            let pfxFilePath = interpolateString(clientCert?.pfxFilePath, interpolationOptions);
            pfxFilePath = path.isAbsolute(pfxFilePath) ? pfxFilePath : path.join(collectionPath, pfxFilePath);
            httpsAgentRequestFields['pfx'] = fs.readFileSync(pfxFilePath);
          } catch (err) {
            console.error('Error reading pfx file', err);
            throw new Error('Error reading pfx file' + err);
          }
        }
        httpsAgentRequestFields['passphrase'] = interpolateString(clientCert.passphrase, interpolationOptions);
        break;
      }
    }
  }

  /**

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Read the appended original error (ENOENT vs EACCES) - it tells you which file and why.
  2. Verify both certFilePath and keyFilePath exist at the resolved location and are readable.
  3. If the path uses interpolation, confirm the variable resolves to a non-empty string.
  4. Use an absolute path to remove ambiguity, or ensure a relative path is relative to the collection dir.

Example fix

// before - env var unset, path becomes '.../undefined/client.crt'
certFilePath: "{{certsDir}}/client.crt"
// after - set the var, or use an absolute path
certFilePath: "/etc/bruno-certs/client.crt"
Defensive patterns

Strategy: try-catch

Validate before calling

const fs = require('fs');
const certPathsReadable = (certFilePath, keyFilePath) => {
  for (const p of [certFilePath, keyFilePath]) {
    if (!p || typeof p !== 'string') return false;
    try { fs.accessSync(p, fs.constants.R_OK); } catch { return false; }
  }
  return true;
};

Try / catch

try {
  await sendRequestWithClientCert(req);
} catch (e) {
  if (/reading cert\/key file/i.test(e.message)) {
    // inspect the appended original error for which file and the errno (ENOENT/EACCES)
  }
}

Prevention

When it happens

Trigger: The configured cert/key path doesn't exist; the file exists but Bruno lacks read permission; interpolation of a variable in the path yielded undefined so `path.join(collectionPath, undefined)` produced an invalid path; the path points to a directory; a relative path resolved against the wrong collection root.

Common situations: Moving a collection without moving the certs; an env var referenced in the path isn't set; a Windows path on Linux or vice versa; permission changes after a system update.

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/3c78f858d0dc9327. Report an issue: GitHub.