grpc/grpc-go · error

credentials: failed to append certificates

Error message

credentials: failed to append certificates

What it means

NewClientTLSFromFileWithALPNDisabled read the cert file successfully but x509.CertPool.AppendCertsFromPEM returned false, meaning the bytes contained no PEM-encoded certificate blocks that Go's parser could add. This is the experimental ALPN-disabled variant of the standard credentials helper; it surfaces a malformed or empty CA bundle.

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}}), nil

View on GitHub (pinned to 03255a9237)

Solutions

  1. Confirm the file is PEM-encoded and contains at least one 'BEGIN CERTIFICATE' block: `openssl x509 -in <file> -noout -text`.
  2. If the cert is DER, convert with `openssl x509 -inform DER -in cert.der -out cert.pem`.
  3. Check the file is non-empty and is the CA/root bundle, not the private key or leaf-only chain (this helper expects root CAs).

Example fix

// before
creds, err := expcreds.NewClientTLSFromFileWithALPNDisabled("/tls/server.key", "example.com")

// after
creds, err := expcreds.NewClientTLSFromFileWithALPNDisabled("/tls/ca.crt", "example.com")
Defensive patterns

Strategy: validation

Validate before calling

import (
    "crypto/x509"
    "encoding/pem"
    "os"
)

func validPEMCABundle(path string) error {
    b, err := os.ReadFile(path)
    if err != nil { return err }
    pool := x509.NewCertPool()
    if !pool.AppendCertsFromPEM(b) {
        return errors.New("file has no PEM CERTIFICATE blocks")
    }
    if pem.Decode(b) == nil { return errors.New("not PEM-encoded") }
    return nil
}

Try / catch

creds, err := expcreds.NewClientTLSFromFileWithALPNDisabled(path, sni)
if err != nil { return fmt.Errorf("load CA bundle %s: %w", path, err) }

Prevention

When it happens

Trigger: Passing a path to a DER-encoded cert, a private key file, an HTML error page, or an empty file to NewClientTLSFromFileWithALPNDisabled. Also triggered when the PEM has only a key block (BEGIN PRIVATE KEY) and no CERTIFICATE blocks.

Common situations: Mounting the wrong secret in Kubernetes (key instead of cert); pointing at a symlink that resolves to nothing; downloading a CA bundle over HTTP and getting a 404 HTML body; using a cert in DER format instead of PEM.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/3c0a3bf022490e77. Report an issue: GitHub.