grafana/k6 · error
failed to load TLS credentials from file: %w
Error message
failed to load TLS credentials from file: %w
What it means
When the insights gRPC client is configured with a TLS cert file (TLSConfig.CertFile), dial options construction calls credentials.NewClientTLSFromFile (internal/cloudapi/insights/client.go:225-229). Any failure reading or parsing that file - missing path, permission denied, content that is not a PEM certificate bundle - returns this wrapped error and Dial aborts.
Source
Thrown at internal/cloudapi/insights/client.go:228
if cfg.ConnectConfig.Block {
opts = append(opts, grpc.WithBlock()) //nolint:staticcheck
}
if cfg.ConnectConfig.FailOnNonTempDialError {
opts = append(opts, grpc.FailOnNonTempDialError(true)) //nolint:staticcheck
}
if cfg.ConnectConfig.Dialer != nil {
opts = append(opts, grpc.WithContextDialer(cfg.ConnectConfig.Dialer))
}
if cfg.TLSConfig.Insecure { //nolint: nestif
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
} else {
if cfg.TLSConfig.CertFile != "" {
creds, err := credentials.NewClientTLSFromFile(cfg.TLSConfig.CertFile, "")
if err != nil {
return nil, fmt.Errorf("failed to load TLS credentials from file: %w", err)
}
opts = append(opts, grpc.WithTransportCredentials(creds))
} else {
opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS13})))
}
}
if cfg.AuthConfig.Enabled {
opts = append(opts, grpc.WithPerRPCCredentials(newPerRPCCredentials(cfg.AuthConfig)))
}
rI, err := retryInterceptor(cfg.RetryConfig)
if err != nil {
return nil, fmt.Errorf("failed to create retry interceptors: %w", err)
}
opts = append(opts, grpc.WithChainUnaryInterceptor([]grpc.UnaryClientInterceptor{rI}...))
View on GitHub (pinned to 93accf6570)
Solutions
- Verify the exact path exists and is readable from where k6 runs: 'ls -l /path/ca.pem' inside the same container
- Validate the file is a PEM certificate: 'openssl x509 -in /path/ca.pem -text -noout' (and check the bundle contains certs)
- Use an absolute path in the configuration to avoid working-directory surprises
- Re-mount or re-copy the secret if it is empty/corrupt
Example fix
# before - path valid on the host, not in the container
volumeMounts: [{ name: ca, mountPath: /etc/ca }] # file lands at /etc/ca/ca.pem
config: certFile: /etc/ca.pem # wrong
# after
config: certFile: /etc/ca/ca.pem Defensive patterns
Strategy: validation
Validate before calling
# deployment pre-flight for the insights CA file
CERT=/etc/k6/insights-ca.pem
[ -s "$CERT" ] || { echo "cert file missing/empty: $CERT"; exit 1; }
openssl x509 -in "$CERT" -noout >/dev/null || { echo "not a valid PEM cert: $CERT"; exit 1; } Prevention
- Mount CA secrets at fixed absolute paths and reference exactly those paths in config
- Validate PEM bundles in CI (openssl x509) before any run that uses custom CAs
- Watch for empty Kubernetes secrets - a missing key mounts an empty file
When it happens
Trigger: CertFile set to a path that does not exist in k6's container/filesystem; a mounted secret that is empty or corrupt; a file containing keys but no certificates; relative path resolved against an unexpected working directory.
Common situations: Kubernetes secret mounted at a different path than configured; CI copying the CA with the wrong name; PEM bundle truncated in transit; permissions blocking read.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to create dial options: %w
- failed to dial: %w
- failed to create retry interceptors: %w
- failed to create request from request metadatas: %w
- failed to ingest request metadatas batch: code=%s, msg=%s
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/460cb524a360d8a3.
Report an issue: GitHub.