{"record":{"id":"3c0a3bf022490e77","repo":"grpc/grpc-go","slug":"credentials-failed-to-append-certificates-3c0a3b","errorCode":null,"errorMessage":"credentials: failed to append certificates","messagePattern":"credentials: failed to append certificates","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"experimental/credentials/tls.go","lineNumber":205,"sourceCode":"\treturn NewTLSWithALPNDisabled(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})\n}\n\n// NewClientTLSFromFileWithALPNDisabled constructs TLS credentials from the\n// provided root certificate authority certificate file(s) to validate server\n// connections. If certificates to establish the identity of the client need to\n// be included in the credentials (eg: for mTLS), use NewTLS instead, where a\n// complete tls.Config can be specified.\n// serverNameOverride is for testing only. If set to a non empty string,\n// it will override the virtual host name of authority (e.g. :authority header\n// field) in requests. ALPN verification is disabled.\nfunc NewClientTLSFromFileWithALPNDisabled(certFile, serverNameOverride string) (credentials.TransportCredentials, error) {\n\tb, err := os.ReadFile(certFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcp := x509.NewCertPool()\n\tif !cp.AppendCertsFromPEM(b) {\n\t\treturn nil, fmt.Errorf(\"credentials: failed to append certificates\")\n\t}\n\treturn NewTLSWithALPNDisabled(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil\n}\n\n// NewServerTLSFromCertWithALPNDisabled constructs TLS credentials from the\n// input certificate for server. ALPN verification is disabled.\nfunc NewServerTLSFromCertWithALPNDisabled(cert *tls.Certificate) credentials.TransportCredentials {\n\treturn NewTLSWithALPNDisabled(&tls.Config{Certificates: []tls.Certificate{*cert}})\n}\n\n// NewServerTLSFromFileWithALPNDisabled constructs TLS credentials from the\n// input certificate file and key file for server. ALPN verification is disabled.\nfunc NewServerTLSFromFileWithALPNDisabled(certFile, keyFile string) (credentials.TransportCredentials, error) {\n\tcert, err := tls.LoadX509KeyPair(certFile, keyFile)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn NewTLSWithALPNDisabled(&tls.Config{Certificates: []tls.Certificate{cert}}), nil","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/experimental/credentials/tls.go#L187-L223","documentation":"NewClientTLSFromFileWithALPNDisabled read the cert file but x509.CertPool.AppendCertsFromPEM returned false, meaning the file contained no PEM-encoded certificate blocks. The error is returned with no underlying cause, so the file path and contents are the only lead. This package (experimental/credentials) exists only for clients that violate HTTP/2 ALPN; prefer the stable credentials package when possible.","triggerScenarios":"Calling NewClientTLSFromFileWithALPNDisabled(certFile, serverName) where certFile is empty, contains comments/whitespace only, is the private key instead of the CA cert, is in DER (binary) rather than PEM format, or holds malformed/truncated PEM blocks.","commonSituations":"Swapping the cert and key arguments or passing the server cert when a root CA is expected; downloading a CA bundle that was served as DER; copy-paste introducing a corrupted BEGIN/END CERTIFICATE fence; file truncated by CI artifact transfer; PEM with only a key block (BEGIN PRIVATE KEY) and no CERTIFICATE block.","solutions":["Open certFile and confirm it contains at least one '-----BEGIN CERTIFICATE-----' ... '-----END CERTIFICATE-----' block.","If the file is DER, convert with: openssl x509 -inform DER -in ca.der -out ca.pem -outform PEM, then pass ca.pem.","Make sure you are passing the root CA file, not the private key or server leaf cert.","Re-fetch/regenerate the CA bundle to rule out truncation or copy corruption.","Where ALPN violations are not in play, switch to credentials.NewClientTLSFromFile (stable API) which has the same check and clearer error context."],"exampleFix":"// before\ncreds, err := expcreds.NewClientTLSFromFileWithALPNDisabled(\"server.key\", \"example.com\")\n\n// after\ncreds, err := expcreds.NewClientTLSFromFileWithALPNDisabled(\"ca.pem\", \"example.com\")","handlingStrategy":"validation","validationCode":"func loadPEMCertPool(path string) (*x509.CertPool, error) {\n    b, err := os.ReadFile(path)\n    if err != nil {\n        return nil, err\n    }\n    if !bytes.Contains(b, []byte(\"BEGIN CERTIFICATE\")) {\n        return nil, fmt.Errorf(\"%s contains no PEM CERTIFICATE block\", path)\n    }\n    pool := x509.NewCertPool()\n    if !pool.AppendCertsFromPEM(b) {\n        return nil, fmt.Errorf(\"%s: no usable PEM certificates\", path)\n    }\n    return pool, nil\n}","typeGuard":null,"tryCatchPattern":"creds, err := expcreds.NewClientTLSFromFileWithALPNDisabled(certFile, serverName)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to append certificates\") {\n        log.Fatalf(\"cert file %q is not a valid PEM CA bundle; convert DER->PEM and ensure it has CERTIFICATE blocks\", certFile)\n    }\n    log.Fatalf(\"tls creds: %v\", err)\n}","preventionTips":["Run `openssl x509 -in <file> -text -noout` on the cert before wiring it into the app.","Store the CA bundle as a versioned artifact and assert on PEM header in CI.","Name files explicitly (ca.pem) to avoid swapping in server.key."],"tags":["tls","credentials","certificates","pem"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}