{"record":{"id":"76979d8cd93801dc","repo":"grafana/k6","slug":"failed-to-append-root-certificate-to-the-pool","errorCode":null,"errorMessage":"failed to append root certificate to the pool","messagePattern":"failed to append root certificate to the pool","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/output/opentelemetry/tls.go","lineNumber":36,"sourceCode":"\ttlsConfig := &tls.Config{\n\t\tMinVersion: tls.VersionTLS13,\n\t}\n\n\tif insecureSkipVerify.Valid {\n\t\ttlsConfig.InsecureSkipVerify = insecureSkipVerify.Bool\n\t\tset = true\n\t}\n\n\t// Load the root certificate\n\tif certPath.Valid {\n\t\tb, err := os.ReadFile(certPath.String) //nolint:forbidigo\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read root certificate from %q: %w\", certPath.String, err)\n\t\t}\n\n\t\tcp := x509.NewCertPool()\n\t\tif ok := cp.AppendCertsFromPEM(b); !ok {\n\t\t\treturn nil, errors.New(\"failed to append root certificate to the pool\")\n\t\t}\n\n\t\ttlsConfig.RootCAs = cp\n\t\tset = true\n\t}\n\n\t// Load the client certificate\n\tif clientCertPath.Valid {\n\t\tcert, err := tls.LoadX509KeyPair(clientCertPath.String, clientKeyPath.String)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to load client certificate: %w\", err)\n\t\t}\n\n\t\ttlsConfig.Certificates = []tls.Certificate{cert}\n\t\tset = true\n\t}\n\n\tif !set {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/output/opentelemetry/tls.go#L18-L54","documentation":"Thrown while building TLS config for the OpenTelemetry output when the PEM file at K6_OTEL_TLS_CERTIFICATE exists and was read successfully, but x509.CertPool.AppendCertsFromPEM returned false, meaning the bytes contained no parseable PEM certificate block. This guards against corrupt or misformatted CA bundles before the exporter connects.","triggerScenarios":"Pointing K6_OTEL_TLS_CERTIFICATE at a DER-encoded (binary) CA file instead of PEM; a certificate file that was truncated, mangled by templating, or contains only a private key/certificate chain header without CERTIFICATE blocks; accidentally passing the client key path in the CA field; line-ending corruption (CRLF injection) from Windows tooling.","commonSituations":"Ops teams exporting certs from vaults that re-encode formats; copy-paste errors that drop BEGIN/END lines; mixing up K6_OTEL_TLS_CERTIFICATE (root CA) with K6_OTEL_TLS_CLIENT_CERTIFICATE (mutual TLS pair).","solutions":["Verify the file is PEM: it must contain '-----BEGIN CERTIFICATE-----' blocks; openssl x509 -in ca.pem -text -noout should succeed","Convert DER to PEM: openssl x509 -inform der -in ca.der -out ca.pem","Check you passed the CA bundle path, not the client cert/key (use K6_OTEL_TLS_CLIENT_CERTIFICATE + K6_OTEL_TLS_CLIENT_KEY for mTLS)","Re-export the certificate from the source of truth to repair truncation or CRLF damage"],"exampleFix":"# before\n# ca.der is binary DER -> AppendCertsFromPEM fails\nexport K6_OTEL_TLS_CERTIFICATE=/certs/ca.der\n\n# after\nopenssl x509 -inform der -in /certs/ca.der -out /certs/ca.pem\nexport K6_OTEL_TLS_CERTIFICATE=/certs/ca.pem","handlingStrategy":"validation","validationCode":"# Fail fast on non-PEM CA bundles before running k6:\nCA=${K6_OTEL_TLS_CERTIFICATE:?}\nopenssl x509 -in \"$CA\" -noout 2>/dev/null || { echo \"$CA is not valid PEM\"; exit 1; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate certificates in your provisioning pipeline with openssl before injecting them","Keep PEM files untouched by templating systems (no variable substitution inside cert files)","Distinct paths for root CA vs client cert/key; verify with a checklist when configuring mTLS"],"tags":["k6","opentelemetry","tls","x509","pem","certificates"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}