{"record":{"id":"224638877fc94350","repo":"siyuan-note/siyuan","slug":"failed-to-decode-ca-private-key-pem","errorCode":null,"errorMessage":"failed to decode CA private key PEM","messagePattern":"failed to decode CA private key PEM","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/cert.go","lineNumber":332,"sourceCode":"// ImportCABundle imports a CA certificate and private key from PEM-encoded strings.\nfunc ImportCABundle(caCertPEM, caKeyPEM string) error {\n\tcertBlock, _ := pem.Decode([]byte(caCertPEM))\n\tif certBlock == nil {\n\t\treturn fmt.Errorf(\"failed to decode CA certificate PEM\")\n\t}\n\n\tcaCert, err := x509.ParseCertificate(certBlock.Bytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CA certificate: %w\", err)\n\t}\n\n\tif !caCert.IsCA {\n\t\treturn fmt.Errorf(\"the provided certificate is not a CA certificate\")\n\t}\n\n\tkeyBlock, _ := pem.Decode([]byte(caKeyPEM))\n\tif keyBlock == nil {\n\t\treturn fmt.Errorf(\"failed to decode CA private key PEM\")\n\t}\n\n\t_, err = x509.ParseECPrivateKey(keyBlock.Bytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CA private key: %w\", err)\n\t}\n\n\tcaCertPath := filepath.Join(ConfDir, TLSCACertFilename)\n\tcaKeyPath := filepath.Join(ConfDir, TLSCAKeyFilename)\n\n\tif err := os.WriteFile(caCertPath, []byte(caCertPEM), 0644); err != nil {\n\t\treturn fmt.Errorf(\"failed to write CA certificate: %w\", err)\n\t}\n\n\tif err := os.WriteFile(caKeyPath, []byte(caKeyPEM), 0600); err != nil {\n\t\treturn fmt.Errorf(\"failed to write CA private key: %w\", err)\n\t}\n","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/util/cert.go#L314-L350","documentation":"After validating the CA certificate, ImportCABundle PEM-decodes the supplied private key. If pem.Decode returns no block, the key material is not valid PEM at all (no BEGIN/END delimiters or only whitespace/garbage), so the import fails before any key parsing.","triggerScenarios":"Passing an empty string, a DER-encoded binary key, or text with the PEM headers stripped/renamed as caKeyPEM to ImportCABundle.","commonSituations":"Pasting the key from a 'openssl ec -outform DER' output, copying only the base64 body without the -----BEGIN EC PRIVATE KEY----- wrapper, or accidentally pasting the certificate again instead of the key.","solutions":["Re-export the key in PEM form: 'openssl ec -in ca.key -out ca.key.pem'","Ensure the text contains the full -----BEGIN ... PRIVATE KEY----- / -----END ... PRIVATE KEY----- block including newlines","Check that you are passing the key file's contents, not the certificate file's, to ImportCABundle"],"exampleFix":"// before\ncaKeyPEM := \"MHcCAQEEI...\" // raw base64, no PEM armor\n// after\ncaKeyPEM := \"-----BEGIN EC PRIVATE KEY-----\\n...\\n-----END EC PRIVATE KEY-----\\n\"","handlingStrategy":"validation","validationCode":"func validKeyPEM(pemStr string) bool {\n    block, _ := pem.Decode([]byte(pemStr))\n    return block != nil && strings.Contains(block.Type, \"PRIVATE KEY\")\n}","typeGuard":"if block == nil || !strings.Contains(block.Type, \"PRIVATE KEY\") { return errors.New(\"not a private key PEM\") }","tryCatchPattern":"if err := util.ImportCABundle(caCertPEM, caKeyPEM); err != nil {\n    if strings.Contains(err.Error(), \"failed to decode CA private key PEM\") {\n        // tell user the key text lacks PEM armor\n    }\n}","preventionTips":["Always copy the whole PEM block including BEGIN/END lines and newlines","Never strip PEM armor or paste raw base64/DER key bytes","Double-check you pasted the key file, not the certificate file"],"tags":["tls","pem","private-key"],"backgroundTag":"invalid-argument-format","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}