gohugoio/hugo · error

failed to parse certificate PEM

Error message

failed to parse certificate PEM

What it means

During `--tlsAuto` cert reuse, Hugo PEM-decodes the cached server certificate (`<cacheDir>/_mkcerts/<host>.pem`) before x509 parsing. `pem.Decode` returned nil, meaning the file contains no PEM block at all — it's empty, truncated, or not PEM-encoded.

Source

Thrown at commands/server.go:734

	}

	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())
	}

	return nil
}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Delete the cached certificates (`<hugo cacheDir>/_mkcerts/`) and rerun `hugo server --tlsAuto` so fresh certs are generated.
  2. If supplying your own certs via `--tlsCertFile`/`--tlsKeyFile`, ensure they are PEM-encoded (convert DER with `openssl x509 -inform der -in cert.der -out cert.pem`).
  3. Verify the file isn't empty: `openssl x509 -in <host>.pem -noout` should parse.
Defensive patterns

Strategy: validation

Validate before calling

block, _ := pem.Decode(certBytes)
if block == nil || block.Type != "CERTIFICATE" {
    return errors.New("cert file is not a PEM CERTIFICATE block")
}

Prevention

When it happens

Trigger: `hugo server --tlsAuto` reading a cached `<hostname>.pem` whose contents lack a `-----BEGIN CERTIFICATE-----` block; note verifyCert is called only when both the cached cert and the mkcert rootCA were readable.

Common situations: Interrupted certificate generation leaving a zero-byte or partial file in `_mkcerts`; disk-full during write; manually replacing the cert with a DER/pkcs12 file; sync tools mangling line endings or content of the cache dir.

Related errors


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