{"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/8a468df065a75c1c7cf9f6850f32148746590ea5/commands/server.go#L716-L752","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Delete the cached certificates (`<hugo cacheDir>/_mkcerts/`) and rerun `hugo server --tlsAuto` so fresh certs are generated.","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`).","Verify the file isn't empty: `openssl x509 -in <host>.pem -noout` should parse."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"block, _ := pem.Decode(certBytes)\nif block == nil || block.Type != \"CERTIFICATE\" {\n    return errors.New(\"cert file is not a PEM CERTIFICATE block\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure the file starts with -----BEGIN CERTIFICATE-----","Don't pass DER-encoded or key files where a PEM cert is expected","Keep cert and key in separate, correctly named files"],"tags":["tls","pem","hugo-server","certificates"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}