kubernetes/kubernetes · error

error parsing root-ca-file at %s: %w

Error message

error parsing root-ca-file at %s: %w

What it means

Thrown in newServiceAccountTokenController (service_accounts.go:62) when readCA(RootCAFile) fails. The RootCAFile (--root-ca-file) is bundled into service-account token payloads so pods can trust the API server's serving cert; readCA parses it as a certificate bundle and fails on a missing/unreadable/malformed file. The %s is the configured path, %w the parse error.

Source

Thrown at cmd/kube-controller-manager/app/service_accounts.go:62

func newServiceAccountTokenController(
	ctx context.Context, controllerContext ControllerContext, controllerName string,
	rootClientBuilder clientbuilder.ControllerClientBuilder,
) (Controller, error) {
	if len(controllerContext.ComponentConfig.SAController.ServiceAccountKeyFile) == 0 {
		klog.FromContext(ctx).Info("Controller is disabled because there is no private key", "controller", controllerName)
		return nil, nil
	}

	privateKey, err := keyutil.PrivateKeyFromFile(controllerContext.ComponentConfig.SAController.ServiceAccountKeyFile)
	if err != nil {
		return nil, fmt.Errorf("error reading key for service account token controller: %w", err)
	}

	var rootCA []byte
	if controllerContext.ComponentConfig.SAController.RootCAFile != "" {
		if rootCA, err = readCA(controllerContext.ComponentConfig.SAController.RootCAFile); err != nil {
			return nil, fmt.Errorf("error parsing root-ca-file at %s: %w", controllerContext.ComponentConfig.SAController.RootCAFile, err)
		}
	} else {
		config, err := rootClientBuilder.Config("tokens-controller")
		if err != nil {
			return nil, fmt.Errorf("failed to create Kubernetes client config for %q: %w", "tokens-controller", err)
		}
		rootCA = config.CAData
	}

	client, err := rootClientBuilder.Client("tokens-controller")
	if err != nil {
		return nil, fmt.Errorf("failed to create Kubernetes client for %q: %w", "tokens-controller", err)
	}

	tokenGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, privateKey)
	if err != nil {
		return nil, fmt.Errorf("failed to build token generator: %w", err)
	}

View on GitHub (pinned to b882c60b40)

Solutions

  1. Confirm the path exists and contains a valid PEM-encoded CA certificate bundle.
  2. Fix permissions/ownership so the KCM process can read it.
  3. If you have no dedicated root CA file, clear --root-ca-file to let KCM use the kubeconfig CAData fallback.
  4. Regenerate/refresh the CA bundle from your PKI source.

Example fix

# before: unreadable / wrong content
--root-ca-file=/etc/kubernetes/pki/ca.key
# after
--root-ca-file=/etc/kubernetes/pki/ca.crt
Defensive patterns

Strategy: validation

Validate before calling

if caPath := componentConfig.SAController.RootCAFile; caPath != "" {
    if _, err := readCA(caPath); err != nil {
        return fmt.Errorf("root-ca-file %s unreadable: %w", caPath, err)
    }
}

Try / catch

if rootCA, err = readCA(rootCAPath); err != nil {
    return nil, fmt.Errorf("error parsing root-ca-file at %s: %w", rootCAPath, err)
}

Prevention

When it happens

Trigger: Starting KCM with --root-ca-file set to a path that does not exist, is unreadable, or does not contain valid PEM CA certificates. If the flag is empty the code falls back to the client config's CAData (line 64-69), so this error only fires when a path is explicitly provided but unreadable.

Common situations: Manifest references a CA bundle path that was never created or was rotated away; permissions on /etc/kubernetes/pki/ca.crt too strict; file accidentally contains a private key or CSR instead of a CA cert.

Related errors


AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07). Data as JSON: /api/errors/225f6c8cc32c0daa. Report an issue: GitHub.