valyala/fasthttp · error
cannot load tls key pair from the provided cert data(%d) and
Error message
cannot load tls key pair from the provided cert data(%d) and key data(%d): %w
What it means
Returned by Server.AppendCertEmbed when tls.X509KeyPair fails to parse the in-memory certificate/key byte slices. Same as the file-based variant but for embedded data; the wrapped error includes the byte lengths of the provided data. The server aborts TLS setup because the pair is invalid.
Source
Thrown at server.go:1957
if err != nil {
return err
}
s.mu.Lock()
s.appendCertLocked(&cert)
s.mu.Unlock()
return nil
}
func x509KeyPair(certData, keyData []byte) (tls.Certificate, error) {
if len(certData) == 0 && len(keyData) == 0 {
return tls.Certificate{}, errNoCertOrKeyProvided
}
cert, err := tls.X509KeyPair(certData, keyData)
if err != nil {
return tls.Certificate{}, fmt.Errorf("cannot load tls key pair from the provided cert data(%d) and key data(%d): %w",
len(certData), len(keyData), err)
}
return cert, nil
}
func (s *Server) appendCertLocked(cert *tls.Certificate) {
s.configTLS()
s.TLSConfig.Certificates = append(s.TLSConfig.Certificates, *cert)
}
func (s *Server) configTLS() {
if s.TLSConfig == nil {
s.TLSConfig = &tls.Config{}
}
}
// DefaultConcurrency is the maximum number of concurrent connections
// the Server may serve by default (i.e. if Server.Concurrency isn't set).View on GitHub (pinned to c96f600972)
Solutions
- Check the byte slices are valid PEM: they should start with -----BEGIN CERTIFICATE----- / -----BEGIN ... PRIVATE KEY----- (use bytes.HasPrefix to assert before calling).
- Confirm cert and key are not swapped and form a matching pair (compare moduli via openssl).
- Decrypt password-protected keys at build time or store unencrypted keys with restricted access.
- Fix go:embed patterns to include the correct files and verify with a small test parsing them via tls.X509KeyPair.
Example fix
// before
certData, _ := assets.ReadFile("wrong_cert.bin")
app.AppendCertEmbed(certData, keyData)
// after
certData, _ := assets.ReadFile("certs/fullchain.pem")
keyData, _ := assets.ReadFile("certs/privkey.pem")
if err := app.AppendCertEmbed(certData, keyData); err != nil { log.Fatal(err) } Defensive patterns
Strategy: validation
Validate before calling
func validateCertData(certData, keyData []byte) error {
if !bytes.HasPrefix(certData, []byte("-----BEGIN")) { return errors.New("cert is not PEM") }
if !bytes.Contains(keyData, []byte("PRIVATE KEY")) { return errors.New("key is not PEM") }
if _, err := tls.X509KeyPair(certData, keyData); err != nil { return err }
return nil
} Try / catch
if err := app.AppendCertEmbed(certData, keyData); err != nil {
if strings.Contains(err.Error(), "provided cert data") {
log.Fatalf("embedded cert/key invalid (PEM? swapped?): %v", err)
}
log.Fatal(err)
} Prevention
- Add a unit test that parses embedded cert/key with tls.X509KeyPair at build time.
- Verify go:embed patterns match the intended PEM files.
- Never embed encrypted keys; store keys unencrypted with restricted file access.
- Assert PEM headers before passing data to AppendCertEmbed.
When it happens
Trigger: Calling AppendCertEmbed with certData/keyData that are not valid PEM, don't form a matching pair, are swapped (cert passed as key), are empty-prefixed/garbage bytes, or come from go:embed paths embedding the wrong files.
Common situations: Embedding encrypted (password-protected) keys; passing DER-encoded blobs instead of PEM; accidentally embedding the CSR or fullchain in the key slot; build pipeline injecting placeholder bytes.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- cannot determine tls server name from addr %q: %w
- cannot load tls key pair from cert file=%q and key file=%q:
- fasthttp: hostclient can't follow redirects to a different p
- fasthttp: tls handshake timed out
- must implement readat
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/bd83d08dab2f26d8.
Report an issue: GitHub.