grafana/k6 · error
failed to append root certificate to the pool
Error message
failed to append root certificate to the pool
What it means
When K6_OTEL_TLS_CERTIFICATE points at a root CA for the OTel exporter's TLS connection, k6 reads the file and feeds it to x509.CertPool.AppendCertsFromPEM. If the file was read successfully but does not contain parseable PEM certificate blocks (e.g., it is DER-encoded binary, a malformed bundle, or not a certificate at all), the append fails and the output returns this error.
Solutions
- Convert DER to PEM: openssl x509 -inform der -in ca.cer -out ca.pem and point K6_OTEL_TLS_CERTIFICATE at ca.pem
- Verify the file first: openssl x509 -in ca.pem -noout -subject (or check it starts with '-----BEGIN CERTIFICATE-----')
- Re-download/export the CA bundle from the source that issued it instead of hand-editing
Example fix
# before export K6_OTEL_TLS_CERTIFICATE=/etc/certs/ca.cer # DER-encoded k6 run -o opentelemetry script.js # after openssl x509 -inform der -in /etc/certs/ca.cer -out /etc/certs/ca.pem export K6_OTEL_TLS_CERTIFICATE=/etc/certs/ca.pem k6 run -o opentelemetry script.js
Defensive patterns
Strategy: validation
Validate before calling
// Shell: verify PEM before the run
ca="${K6_OTEL_TLS_CERTIFICATE:-}"
if [ -n "$ca" ]; then
head -1 "$ca" | grep -q '^-----BEGIN CERTIFICATE-----' \
|| { echo "$ca is not PEM; convert with: openssl x509 -inform der -in $ca -out $ca.pem" >&2; exit 1; }
fi
k6 run -o opentelemetry script.js Type guard
// Go
func isPEMCert(b []byte) bool {
block, _ := pem.Decode(b)
return block != nil && block.Type == "CERTIFICATE"
} Prevention
- Convert DER certificates to PEM once, at provisioning time, not per test run
- Verify CA files with 'openssl x509 -in ca.pem -noout -subject' before wiring them into CI
- Prefer re-exporting the bundle from the issuing CA over hand-editing PEM files
When it happens
Trigger: K6_OTEL_TLS_CERTIFICATE pointing at a DER/binary .crt file (common for Windows-exported CAs); a truncated or concatenated-with-garbage PEM bundle; a proxy that saved an HTML error page as ca.pem.
Common situations: Corporate proxy/CA setups where the provided CA file is DER, not PEM; manual copy-paste of certs that lost the BEGIN/END lines; expired-then-regenerated bundles with stray bytes.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to decode PEM key
- gRPC exporter endpoint is required
- grpc protocol does not support URL path
- HTTP exporter endpoint is required
- HTTP exporter endpoint must only be host and port, no scheme
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/76979d8cd93801dc.
Report an issue: GitHub.
Appendix: source
Thrown at internal/output/opentelemetry/tls.go:36
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS13,
}
if insecureSkipVerify.Valid {
tlsConfig.InsecureSkipVerify = insecureSkipVerify.Bool
set = true
}
// Load the root certificate
if certPath.Valid {
b, err := os.ReadFile(certPath.String) //nolint:forbidigo
if err != nil {
return nil, fmt.Errorf("failed to read root certificate from %q: %w", certPath.String, err)
}
cp := x509.NewCertPool()
if ok := cp.AppendCertsFromPEM(b); !ok {
return nil, errors.New("failed to append root certificate to the pool")
}
tlsConfig.RootCAs = cp
set = true
}
// Load the client certificate
if clientCertPath.Valid {
cert, err := tls.LoadX509KeyPair(clientCertPath.String, clientKeyPath.String)
if err != nil {
return nil, fmt.Errorf("failed to load client certificate: %w", err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
set = true
}
if !set {View on GitHub (pinned to 01ffac6f24)