Skip to content

Errors and log output

The one sentinel error you should handle

ErrElevationUnavailable

var ErrElevationUnavailable = errors.New(
    "localca: administrator privileges are required to install into the system trust " +
        "store, but no elevation is available (not root, and no interactive terminal to prompt)",
)

Returned when a system-store install needs administrator privileges that cannot be obtained: the process is not root, and either sudo is missing from PATH or standard input is not an interactive terminal.

It is the one error a consuming tool is expected to branch on, because it is not a fault — it is the environment telling you to take a different path. Match it with errors.Is; it survives the wrapping that Install applies:

if _, err := authority.Install(ctx); errors.Is(err, localca.ErrElevationUnavailable) {
    // Fall back: NSS only, an untrusted self-signed certificate, or tell the
    // user to run the install once from a terminal.
}

Everything else localca returns is a fault to report, not a condition to branch on.

Every error localca produces itself

All are created with github.com/cockroachdb/errors, so they carry a stack trace and unwrap normally. Errors from the standard library or the trust-store backend are wrapped with a short context prefix and passed through.

Message Returned by What it means
localca: Config.DataDir is required New, EnsureServed Config.DataDir was empty.
localca: EnsureServed needs at least one host EnsureServed The hosts slice was empty.
localca: no hosts for leaf certificate Authority.Leaf Leaf was called with no host arguments.
localca: no root CA provisioned (call Install or EnsureServed first) Authority.Installed, Authority.Leaf No root has been minted yet. Neither call mints one.
localca: root cert present but key missing any call that loads the root rootCA.pem exists but rootCA-key.pem does not. See recovering from a half-written root.
localca: stored root cert is not valid PEM any call that loads the root rootCA.pem is not a PEM CERTIFICATE block.
localca: stored root key is not valid PEM any call that loads the root rootCA-key.pem is not a PEM EC PRIVATE KEY block.

A leaf that fails to parse is not an error: it is treated as an empty cache and re-minted.

Wrapped errors and their prefixes

These prefixes tell you which step failed. The wrapped cause carries the detail.

Prefix Step
creating data dir creating DataDir
reading <file>, writing <file>, flushing <file>, setting mode on <file>, renaming <file> into place, creating temp file for <file>, removing <file> the atomic file write, at the named stage
generating root key, creating root certificate, parsing root certificate, marshalling root key minting the root
generating leaf key, creating leaf certificate, marshalling leaf key minting a leaf
generating certificate serial drawing the random serial — reached when minting either the root or a leaf
parsing stored root certificate, parsing stored root key loading a stored root whose PEM decoded but whose contents did not parse
assembling leaf key pair turning the minted PEM into a tls.Certificate
installing root into trust store the trust-store install
removing root from trust store the trust-store uninstall
encoding trust marker, writing trust marker updating trust-install.json
pre-authorising sudo for the trust-store install the sudo -v pre-warm failed or was cancelled — typically a wrong password, or the user pressing Ctrl-C at the prompt

installing root into trust store appears twice in a failed install: once from the trust-store backend and once from Authority.Install wrapping it. That is cosmetic; errors.Is and the underlying cause are unaffected.

What localca logs, and when

localca logs through an injected *slog.Logger. The default is a discard handler, so nothing is logged unless you pass WithLogger. That includes the expiry warning below, which is the only advance notice you get that your local CA is running out.

There are exactly two lines.

INFO — a root is about to be installed

installing a local development CA into the trust store so this tool can serve HTTPS
locally; reverse with Uninstall

Attribute: common_name — the root's Common Name.

Emitted by Install (including the Install that EnsureServed performs) only on the call that mints the root, immediately before the trust-store install and therefore immediately before any password prompt. It exists so a user who is suddenly asked for a password can see why. If you attach no logger, the prompt appears with no explanation.

Loading an existing root does not log it, so this line appears once in the life of a data directory.

WARN — the root CA is expiring

root CA expiring soon — leaf lifetime clamped to the root's; re-run Install to renew the
local CA

Attributes: common_name, and root_not_after — the root's expiry timestamp.

Emitted whenever a leaf has to be shortened because the requested LeafTTL would have run past the root's expiry. In practice that means the root has less than one leaf lifetime left — by default, less than 90 days. It repeats on every mint from then on.

The fix is to renew the root: Uninstall with Purge(), delete the cached leaf files, then provision again. See what Purge leaves behind.

What is deliberately not logged

  • The private key, and any part of it.
  • The certificate contents. Only the Common Name and the root's expiry appear in log attributes.
  • The trust-store commands and their output. sudo, certutil and security write their own messages to the terminal directly; localca does not capture or re-emit them, which is why a failing install can print output that does not appear in your structured logs.