gohugoio/hugo · error
failed to parse root certificate
Error message
failed to parse root certificate
What it means
With `--tlsAuto`, Hugo reuses mkcert-generated certificates cached under Hugo's cache dir, but first verifies the cached cert against the mkcert root CA (`$CAROOT/rootCA.pem`). This error means `x509.NewCertPool().AppendCertsFromPEM` found no valid certificate in that root file — the mkcert root CA PEM is corrupt or not actually PEM.
Source
Thrown at commands/server.go:729
if err := c.verifyCert(rootPem, certPEM, hostname); err == nil {
c.r.Println("Using existing", c.tlsCertFile, "and", c.tlsKeyFile)
return nil
}
}
}
c.r.Println("Creating TLS certificates in", keyDir)
// Yes, this is unfortunate, but it's currently the only way to use Mkcert as a library.
os.Args = []string{"-cert-file", c.tlsCertFile, "-key-file", c.tlsKeyFile, hostname}
return mclib.RunMain()
}
func (c *serverCommand) verifyCert(rootPEM, certPEM []byte, name string) error {
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(rootPEM)
if !ok {
return fmt.Errorf("failed to parse root certificate")
}
block, _ := pem.Decode(certPEM)
if block == nil {
return fmt.Errorf("failed to parse certificate PEM")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return fmt.Errorf("failed to parse certificate: %v", err.Error())
}
opts := x509.VerifyOptions{
DNSName: name,
Roots: roots,
}
if _, err := cert.Verify(opts); err != nil {
return fmt.Errorf("failed to verify certificate: %v", err.Error())View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Regenerate the mkcert root: run `mkcert -install` (or delete the CAROOT dir and rerun) to recreate a valid `rootCA.pem`.
- Check the `CAROOT` environment variable points at the directory that actually holds `rootCA.pem`.
- Inspect the file: `openssl x509 -in "$(mkcert -CAROOT)/rootCA.pem" -noout -text` should succeed; if not, replace it.
- Delete Hugo's cached certs (`<cacheDir>/_mkcerts`) so they are recreated after fixing the root.
Defensive patterns
Strategy: validation
Validate before calling
pem, err := os.ReadFile(caFile)
if err != nil { return err }
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(pem) {
return errors.New("CA file contains no valid PEM certificates")
} Prevention
- Verify the CA file with `openssl x509 -in ca.pem -noout -text` before use
- Regenerate certs with `hugo server trust` / mkcert rather than hand-editing PEM files
- Check the file isn't empty or a private key by mistake
When it happens
Trigger: `hugo server --tlsAuto` when `<CAROOT>/rootCA.pem` exists but contains no parsable PEM certificate blocks (truncated file, wrong encoding such as DER, empty file, or unrelated content).
Common situations: A corrupted or half-written mkcert install; `CAROOT` env pointing at the wrong directory; restoring dotfiles/backups that mangled `rootCA.pem`; converting the root cert to DER or replacing it manually.
Related errors
- failed to parse certificate PEM
- failed to parse certificate: %v
- failed to verify certificate: %v
- cannot use --renderToMemory with --destination
- failed to create baseURL from %q: %s
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/306a019b78fe59f6.json.
Report an issue: GitHub ↗.