crowdsecurity/crowdsec · error

failed to load api client certificate: %w

Error message

failed to load api client certificate: %w

What it means

When both cert_path and key_path are configured, Load() calls tls.LoadX509KeyPair to load the client mTLS pair. This error wraps any failure from the Go TLS package: unreadable files, malformed PEM data, or a certificate/key mismatch. It is thrown during config load, before the API client dials the server.

Source

Thrown at pkg/csconfig/api.go:218

		}

		caCertPool, err := x509.SystemCertPool()
		if err != nil {
			log.Warningf("Error loading system CA certificates: %s", err)
		}

		if caCertPool == nil {
			caCertPool = x509.NewCertPool()
		}

		caCertPool.AppendCertsFromPEM(caCert)
		apiclient.CaCertPool = caCertPool
	}

	if l.Credentials.CertPath != "" && l.Credentials.KeyPath != "" {
		cert, err := tls.LoadX509KeyPair(l.Credentials.CertPath, l.Credentials.KeyPath)
		if err != nil {
			return fmt.Errorf("failed to load api client certificate: %w", err)
		}

		apiclient.Cert = &cert
	}

	return nil
}

// local api service configuration
type LocalApiServerCfg struct {
	Enable                        *bool                    `yaml:"enable"`
	ListenURI                     string                   `yaml:"listen_uri,omitempty"` // 127.0.0.1:8080
	ListenSocket                  string                   `yaml:"listen_socket,omitempty"`
	TLS                           *TLSCfg                  `yaml:"tls"`
	DbConfig                      *DatabaseCfg             `yaml:"-"`
	OnlineClient                  *OnlineApiClientCfg      `yaml:"online_client"`
	ProfilesPath                  string                   `yaml:"profiles_path,omitempty"`
	ConsoleConfigPath             string                   `yaml:"console_path,omitempty"`

View on GitHub (pinned to 909b515798)

Solutions

  1. Verify both files exist and are readable: `ls -l <cert> <key>` and `openssl x509 -in cert.pem -noout` / `openssl rsa -in key.pem -check`.
  2. Confirm the cert and key match: compare `openssl x509 -noout -modulus` and `openssl rsa -noout -modulus` outputs.
  3. Regenerate the client pair on the LAPI host (`cscli users add`/`cscli lapi register` flow) and redeploy both files together.
  4. Fix permissions on the key file (often 600 and owned by the service user).
  5. If mTLS is not required, remove cert_path/key_path from the credentials config.

Example fix

// before: mismatched pair
cert_path: /etc/crowdsec/ssl/client-old.crt
key_path: /etc/crowdsec/ssl/client-new.key
// after: matching regenerated pair
cert_path: /etc/crowdsec/ssl/client.crt
key_path: /etc/crowdsec/ssl/client.key
Defensive patterns

Strategy: validation

Validate before calling

if certPath != "" && keyPath != "" {
    if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil {
        return fmt.Errorf("client mTLS pair invalid: %w", err)
    }
}

Try / catch

if err := creds.Load(); err != nil {
    if strings.Contains(err.Error(), "failed to load api client certificate") {
        return fmt.Errorf("mTLS pair invalid, regenerate with 'cscli lapi register': %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Credentials.CertPath and Credentials.KeyPath are both set and tls.LoadX509KeyPair fails: missing or unreadable file, invalid PEM blocks, key encrypted with a passphrase, or cert/key derived from different CSRs.

Common situations: Client cert and key from different enrollments copied into the config; cert file containing only the CA cert rather than the client cert; key regenerated after the certificate was issued; SELinux or mount permissions blocking the key file; files pasted without the BEGIN/END lines.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/d7ac7e62c0d7655b. Report an issue: GitHub.