{"record":{"id":"db63f25d3a36cc54","repo":"gohugoio/hugo","slug":"failed-to-parse-certificate-pem","errorCode":null,"errorMessage":"failed to parse certificate PEM","messagePattern":"failed to parse certificate PEM","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"commands/server.go","lineNumber":734,"sourceCode":"\t}\n\n\tc.r.Println(\"Creating TLS certificates in\", keyDir)\n\n\t// Yes, this is unfortunate, but it's currently the only way to use Mkcert as a library.\n\tos.Args = []string{\"-cert-file\", c.tlsCertFile, \"-key-file\", c.tlsKeyFile, hostname}\n\treturn mclib.RunMain()\n}\n\nfunc (c *serverCommand) verifyCert(rootPEM, certPEM []byte, name string) error {\n\troots := x509.NewCertPool()\n\tok := roots.AppendCertsFromPEM(rootPEM)\n\tif !ok {\n\t\treturn fmt.Errorf(\"failed to parse root certificate\")\n\t}\n\n\tblock, _ := pem.Decode(certPEM)\n\tif block == nil {\n\t\treturn fmt.Errorf(\"failed to parse certificate PEM\")\n\t}\n\tcert, err := x509.ParseCertificate(block.Bytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse certificate: %v\", err.Error())\n\t}\n\n\topts := x509.VerifyOptions{\n\t\tDNSName: name,\n\t\tRoots:   roots,\n\t}\n\n\tif _, err := cert.Verify(opts); err != nil {\n\t\treturn fmt.Errorf(\"failed to verify certificate: %v\", err.Error())\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":716,"sourceCodeEnd":752,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/commands/server.go#L716-L752","documentation":"`verifyCert` decodes the cached site certificate PEM with `pem.Decode`; a `nil` block means the input is not a PEM-encoded certificate. Hugo returns this plain error before attempting `x509.ParseCertificate`. It indicates the cached `.pem` cert file is corrupt.","triggerScenarios":"Fires when the cached `cert.pem` (at `keyDir/<hostname>.pem`) is empty, not PEM-formatted, or contains only a private key block instead of a certificate.","commonSituations":"The site cert PEM was overwritten with key-only content; truncated by a failed write/interrupt; an editor saved it as a different encoding; the file was swapped with a non-PEM artifact.","solutions":["Inspect the cached cert PEM file and confirm it has a `-----BEGIN CERTIFICATE-----` block.","Delete the corrupted `_mkcerts/<hostname>.pem` and key so Hugo regenerates them.","Re-run `mkcert <hostname>` if managing certs manually.","Ensure no process truncates the cache directory mid-run."],"exampleFix":"// before\n// _mkcerts/localhost.pem contains only PRIVATE KEY block\n// after\n// rm _mkcerts/localhost*.pem && hugo server --tlsAuto  (regenerates)","handlingStrategy":"validation","validationCode":"import \"encoding/pem\"\nfunc validateCertPEM(path string) error {\n  b, err := os.ReadFile(path)\n  if err != nil { return err }\n  if pem.Decode(b) == nil { return fmt.Errorf(\"not a valid PEM certificate\") }\n  return nil\n}","typeGuard":"null","tryCatchPattern":"// If the cached cert PEM is unparseable, delete and regenerate.\nif _, err := pem.Decode(certPEM); err == nil { /* invalid */ }\n// fallback: re-run mkcert or Hugo --tlsAuto","preventionTips":["Don't overwrite cert PEM files with key-only content.","Validate cached certs with `openssl x509 -in cert.pem -noout -text`.","Treat the `_mkcerts` cache as disposable; regenerate when in doubt."],"tags":["hugo","server","tls","certificate","pem"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}