router-for-me/CLIProxyAPI · error

home tls: read ca-cert: %w

Error message

home tls: read ca-cert: %w

What it means

Wraps os.ReadFile failure in internal/home/client.go when reading the configured CA certificate file for the home TLS root pool. The %w preserves the os error — almost always 'no such file or directory' or 'permission denied' for the ca-cert path.

Source

Thrown at internal/home/client.go:653

	if clientCertPath != "" || clientKeyPath != "" {
		if clientCertPath == "" || clientKeyPath == "" {
			return nil, fmt.Errorf("home tls: client certificate and key must be set together")
		}
		certPair, errLoad := tls.LoadX509KeyPair(clientCertPath, clientKeyPath)
		if errLoad != nil {
			return nil, fmt.Errorf("home tls: load client certificate: %w", errLoad)
		}
		tlsConfig.Certificates = []tls.Certificate{certPair}
	}

	caCertPath := strings.TrimSpace(cfg.CACert)
	if caCertPath == "" {
		return tlsConfig, nil
	}

	caCertPEM, errRead := os.ReadFile(caCertPath)
	if errRead != nil {
		return nil, fmt.Errorf("home tls: read ca-cert: %w", errRead)
	}

	certPool, errPool := x509.SystemCertPool()
	if errPool != nil || certPool == nil {
		certPool = x509.NewCertPool()
	}
	if !certPool.AppendCertsFromPEM(caCertPEM) {
		return nil, fmt.Errorf("home tls: ca-cert contains no PEM certificates")
	}
	tlsConfig.RootCAs = certPool

	return tlsConfig, nil
}

func (c *Client) commandClient() (*redis.Client, error) {
	if c == nil || c.dispatchFenced.Load() {
		return nil, ErrDispatchFenced
	}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Verify the exact path exists from the process's perspective: ls -l <path> as the service user
  2. Use absolute paths in config to avoid working-directory dependence
  3. Fix permissions (0644 readable) or ownership if it is a permission error
  4. If the CA was never copied, distribute it from the home server

Example fix

# before
home:
  tls:
    ca-cert: ca.pem  # relative, breaks under systemd/container

# after
home:
  tls:
    ca-cert: /etc/cliproxy/ca.pem
Defensive patterns

Strategy: validation

Validate before calling

if cfg.TLS.CACert != "" {
    if _, err := os.Stat(cfg.TLS.CACert); err != nil {
        return fmt.Errorf("home ca-cert %s not accessible: %w", cfg.TLS.CACert, err)
    }
}

Try / catch

if err != nil && errors.Is(err, fs.ErrNotExist) {
    log.Errorf("ca-cert path %s missing — distribute CA or fix mount", cfg.TLS.CACert)
}

Prevention

When it happens

Trigger: home.tls.ca-cert points at a path that does not exist at runtime, or exists but is not readable by the process user; relative path resolved against a different working directory in a container/service.

Common situations: CA not yet distributed to the node; path typo or changed mount point in Kubernetes (secret not mounted); service running with a different WORKDIR so a relative path breaks; file owned root-only.

Understand the failure class

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/00cdc538613b5143. Report an issue: GitHub.