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

  1. Regenerate the mkcert root: run `mkcert -install` (or delete the CAROOT dir and rerun) to recreate a valid `rootCA.pem`.
  2. Check the `CAROOT` environment variable points at the directory that actually holds `rootCA.pem`.
  3. Inspect the file: `openssl x509 -in "$(mkcert -CAROOT)/rootCA.pem" -noout -text` should succeed; if not, replace it.
  4. 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

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


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/306a019b78fe59f6.json. Report an issue: GitHub ↗.