gohugoio/hugo · error
failed to parse certificate
Error message
failed to parse certificate: %v
What it means
After a PEM block is decoded, `verifyCert` calls `x509.ParseCertificate(block.Bytes)` to turn the DER bytes into a certificate. This wraps an ASN.1/x509 parse failure, meaning the PEM looked valid but the certificate bytes are malformed. `%v` is the x509 error string.
Solutions
- Re-verify the certificate with `openssl x509 -in cert.pem -noout -text` to reproduce the parse error.
- Delete the cached `_mkcerts` cert and regenerate via mkcert or Hugo's `--tlsAuto`.
- Re-fetch the certificate from its original issuer if supplied externally.
Example fix
// before // $ openssl x509 -in _mkcerts/localhost.pem -noout -text -> unable to load certificate // after // rm _mkcerts/localhost*.pem && mkcert localhost
Defensive patterns
Strategy: validation
Validate before calling
import (
"crypto/x509"
"encoding/pem"
)
func validateCert(path string) error {
b, err := os.ReadFile(path)
if err != nil { return err }
block, _ := pem.Decode(b)
if block == nil { return fmt.Errorf("no PEM block") }
if _, err := x509.ParseCertificate(block.Bytes); err != nil { return err }
return nil
} Type guard
null
Try / catch
// On parse failure, discard the cached cert and let mkcert reissue.
if _, err := x509.ParseCertificate(block.Bytes); err != nil {
os.Remove(certFile); os.Remove(keyFile)
// re-provision on next run
} Prevention
- Cross-check certs with openssl before relying on them.
- Regenerate cached certs from a known-good source when they fail to parse.
- Avoid hand-editing cert files.
When it happens
Trigger: Fires when the decoded PEM block is a certificate block (`CERTIFICATE`) but its DER bytes fail x509 parsing — truncated, corrupted, or not actually an X.509 cert despite the header.
Common situations: A `.pem` file that wraps a CSR or a non-cert block under a CERTIFICATE header; byte-level corruption from a bad download/copy; a PEM produced by a broken cert tool.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to verify certificate
- failed to parse certificate PEM
- failed to parse root certificate
- --appendPort=false not supported when in multihost mode
- cannot use --renderToMemory with --destination
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/34560b93dc415987.
Report an issue: GitHub.
Appendix: source
Thrown at commands/server.go:738
// 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
}
func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
flags := cd.CobraCommand.Flags()
var cerr error
c.withConf(func(conf *commonConfig) {View on GitHub (pinned to 52c9bd7908)