argoproj/argo-workflows · error

failed to read certificate file: %w

Error message

failed to read certificate file: %w

What it means

When the rest.Config has no inline CertData, ClaimSetWithX509 falls back to reading the certificate from restConfig.CertFile with os.ReadFile. If the file cannot be opened (missing, unreadable, wrong path), the OS error is wrapped as 'failed to read certificate file: %w'. The operation aborts because no identity claims can be derived without the certificate.

Source

Thrown at server/auth/serviceaccount/claims.go:91

func ClaimSetWithX509(restConfig *rest.Config) (*types.Claims, error) {
	var cert *x509.Certificate
	var err error
	if len(restConfig.CertData) > 0 {
		// Decode certificate from memory data
		block, _ := pem.Decode(restConfig.CertData)
		if block == nil || block.Type != "CERTIFICATE" {
			return nil, fmt.Errorf("failed to parse certificate PEM")
		}
		cert, err = x509.ParseCertificate(block.Bytes)
		if err != nil {
			return nil, fmt.Errorf("failed to parse certificate: %w", err)
		}
	} else {
		// Load certificate from file
		data, err := os.ReadFile(restConfig.CertFile)
		if err != nil {
			return nil, fmt.Errorf("failed to read certificate file: %w", err)
		}
		block, _ := pem.Decode(data)
		if block == nil || block.Type != "CERTIFICATE" {
			return nil, fmt.Errorf("failed to parse certificate PEM")
		}
		cert, err = x509.ParseCertificate(block.Bytes)
		if err != nil {
			return nil, fmt.Errorf("failed to parse certificate: %w", err)
		}
	}

	if cert == nil {
		return nil, fmt.Errorf("failed to parse certificate")
	}

	// Extract username from CommonName (CN)
	username := cert.Subject.CommonName

View on GitHub (pinned to 35bff19146)

Solutions

  1. Check the file exists and is readable: `ls -l <CertFile path>` and `head -1 <path>` should show '-----BEGIN CERTIFICATE-----'
  2. Fix the kubeconfig's users[].user.client-certificate path or mount the client cert secret into the argo-server pod
  3. If running in-cluster, provide inline CertData (base64 of the cert) instead of a file path so no filesystem dependency exists

Example fix

// before
restConfig.CertFile = "/secrets/tls/client.crt" // file not mounted
// after: embed the data so no file read is needed
restConfig.CertData = clientCertPEMBytes
Defensive patterns

Strategy: validation

Validate before calling

func validateCertFile(path string) error {
    data, err := os.ReadFile(path)
    if err != nil {
        return fmt.Errorf("cert file %q unreadable: %w", path, err)
    }
    return nil
}
// call before constructing rest.Config with CertFile

Try / catch

claims, err := ClaimSetWithX509(restConfig)
if err != nil && strings.Contains(err.Error(), "failed to read certificate file") {
    // fall back or surface a config-fix message
}

Prevention

When it happens

Trigger: restConfig.CertData is empty, restConfig.CertFile points to a path that does not exist, is a directory, or the process lacks read permission, so os.ReadFile returns an error which is wrapped and returned.

Common situations: Mounted secret volume path changed or not mounted yet; client-certificate file deleted after kubeconfig was flattened; argo-server running with a different service account that cannot read the cert path; typo in certFile path in kubeconfig.

Understand the failure class

Related errors


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