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

  1. Verify the caCert path exists and is readable by the process (ls -l; check mount)
  2. Fix the path in your CLI flag / env var / config so it points at the actual CA PEM file
  3. If in Kubernetes, confirm the secret is mounted into the pod (check volumes/volumeMounts) and the container has read access
  4. 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

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

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/76770829e8156ee9. Report an issue: GitHub.