argoproj/argo-workflows · error
failed to read certificate authority: %w
Error message
failed to read certificate authority: %w
What it means
GetClientTLSConfig could not read the CA certificate file at the given path. The wrapped os.ReadFile error names the actual OS problem (missing file, permissions, etc.). This is used to build the RootCAs pool for verifying the Argo server certificate.
Source
Thrown at util/tls/tls.go:169
}, nil
}
// GetClientTLSConfig creates a TLS 1.2 or newer configuration for client connections.
// Client certificate authentication requires both clientCert and clientKey. If caCert is provided,
// the certificate authority is used instead of the system roots to verify the server certificate.
// The insecureSkipVerify parameter controls whether the server's certificate is verified.
func GetClientTLSConfig(clientCert, clientKey, caCert string, insecureSkipVerify bool) (*tls.Config, error) {
tlsConfig := &tls.Config{
InsecureSkipVerify: insecureSkipVerify,
MinVersion: tls.VersionTLS12,
}
if (clientCert == "") != (clientKey == "") {
return nil, fmt.Errorf("client certificate authentication requires both clientCert and clientKey")
}
if caCert != "" {
caPEM, err := os.ReadFile(caCert)
if err != nil {
return nil, fmt.Errorf("failed to read certificate authority: %w", err)
}
certPool := x509.NewCertPool()
if ok := certPool.AppendCertsFromPEM(caPEM); !ok {
return nil, fmt.Errorf("failed to parse certificate authority %q", caCert)
}
tlsConfig.RootCAs = certPool
}
if clientCert != "" && clientKey != "" {
cert, err := tls.LoadX509KeyPair(clientCert, clientKey)
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
return tlsConfig, nil
}
View on GitHub (pinned to 35bff19146)
Solutions
- Verify the caCert path exists and is readable by the process (ls -l; check mount)
- Fix the path in your CLI flag / env var / config so it points at the actual CA PEM file
- If in Kubernetes, confirm the secret is mounted into the pod (check volumes/volumeMounts) and the container has read access
- Copy the CA bundle to the client host if running the CLI outside the cluster
Example fix
// before
config, err := tls.GetClientTLSConfig("", "", "/etc/argo/ca.crt", false)
// after (verify file exists first)
if _, err := os.Stat("/etc/argo/ca.crt"); err != nil { /* fix path/mount */ }
config, err := tls.GetClientTLSConfig("", "", "/etc/argo/server-ca.crt", false) Defensive patterns
Strategy: validation
Validate before calling
func caReadable(path string) error {
if path == "" { return nil }
fi, err := os.Stat(path)
if err != nil { return fmt.Errorf("CA file %q: %w", path, err) }
if fi.Mode()&0o400 == 0 { return fmt.Errorf("CA file %q not readable", path) }
return nil
} Try / catch
var pathErr *fs.PathError
config, err := tls.GetClientTLSConfig(cert, key, caCert, insecure)
if err != nil && errors.As(err, &pathErr) {
return fmt.Errorf("CA path %q unusable, check mount/permissions: %w", caCert, err)
} Prevention
- Verify the CA path exists inside the same container that runs the client
- Check secret volumeMounts when running in Kubernetes
- Use absolute paths; don't rely on host paths that differ in containers
- Test with `kubectl exec` that the file is readable by the process user
When it happens
Trigger: Calling GetClientTLSConfig with a non-empty caCert path that cannot be opened — file does not exist, wrong path, unreadable permissions, or the secret volume isn't mounted yet.
Common situations: Pointing the argo CLI at a CA path from a different machine/host; k8s secret volume not mounted into the pod; path typo; running outside the cluster where the in-cluster CA file doesn't exist; RBAC/volume mount missing after upgrade.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to read certificate file: %w
- failed to parse certificate authority %q
- --client-certificate and --client-key must be provided toget
- failed to create folder path: %w
- request failed with: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/76770829e8156ee9.
Report an issue: GitHub.