grpc/grpc-go · error
credentials: failed to append certificates
Error message
credentials: failed to append certificates
What it means
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.
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.
Example fix
// before
creds, err := expcreds.NewClientTLSFromFileWithALPNDisabled("server.key", "example.com")
// after
creds, err := expcreds.NewClientTLSFromFileWithALPNDisabled("ca.pem", "example.com") Defensive patterns
Strategy: validation
Validate before calling
func loadPEMCertPool(path string) (*x509.CertPool, error) {
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}
if !bytes.Contains(b, []byte("BEGIN CERTIFICATE")) {
return nil, fmt.Errorf("%s contains no PEM CERTIFICATE block", path)
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(b) {
return nil, fmt.Errorf("%s: no usable PEM certificates", path)
}
return pool, nil
} Try / catch
creds, err := expcreds.NewClientTLSFromFileWithALPNDisabled(certFile, serverName)
if err != nil {
if strings.Contains(err.Error(), "failed to append certificates") {
log.Fatalf("cert file %q is not a valid PEM CA bundle; convert DER->PEM and ensure it has CERTIFICATE blocks", certFile)
}
log.Fatalf("tls creds: %v", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- xds: CertificateProvider to fetch identity certificate is…
- xds: CertificateProvider to fetch trusted roots is missing…
- cannot send secure credentials on an insecure connection
- credentials: cannot send secure credentials on an insecure…
- failed to build credentials bundle from bootstrap for
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/3c0a3bf022490e77.
Report an issue: GitHub.
Appendix: source
Thrown at experimental/credentials/tls.go:205
return NewTLSWithALPNDisabled(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})
}
// NewClientTLSFromFileWithALPNDisabled constructs TLS credentials from the
// provided root certificate authority certificate file(s) to validate server
// connections. If certificates to establish the identity of the client need to
// be included in the credentials (eg: for mTLS), use NewTLS instead, where a
// complete tls.Config can be specified.
// serverNameOverride is for testing only. If set to a non empty string,
// it will override the virtual host name of authority (e.g. :authority header
// field) in requests. ALPN verification is disabled.
func NewClientTLSFromFileWithALPNDisabled(certFile, serverNameOverride string) (credentials.TransportCredentials, error) {
b, err := os.ReadFile(certFile)
if err != nil {
return nil, err
}
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM(b) {
return nil, fmt.Errorf("credentials: failed to append certificates")
}
return NewTLSWithALPNDisabled(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil
}
// NewServerTLSFromCertWithALPNDisabled constructs TLS credentials from the
// input certificate for server. ALPN verification is disabled.
func NewServerTLSFromCertWithALPNDisabled(cert *tls.Certificate) credentials.TransportCredentials {
return NewTLSWithALPNDisabled(&tls.Config{Certificates: []tls.Certificate{*cert}})
}
// NewServerTLSFromFileWithALPNDisabled constructs TLS credentials from the
// input certificate file and key file for server. ALPN verification is disabled.
func NewServerTLSFromFileWithALPNDisabled(certFile, keyFile string) (credentials.TransportCredentials, error) {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}
return NewTLSWithALPNDisabled(&tls.Config{Certificates: []tls.Certificate{cert}}), nilView on GitHub (pinned to 0c51461d27)