t8y2/dbx · error

load Neo4j client certificate: %w

Error message

load Neo4j client certificate: %w

What it means

This error wraps any failure that occurs while loading the client certificate/key pair used for mutual TLS with a Neo4j server. neo4jTLSConfigurer calls neo4jauth.NewStaticClientCertificateProvider with the configured cert and key file paths; if either file is missing, unreadable, or the key does not match the certificate, the underlying error is wrapped with this message. It surfaces during driver creation (openDriver), so the driver never opens when it fires.

Source

Thrown at agents/drivers/neo4j-go/driver.go:96

		if err != nil || roots == nil {
			roots = x509.NewCertPool()
		}
		if !roots.AppendCertsFromPEM(certificate) {
			return nil, errors.New("Neo4j CA certificate contains no valid PEM certificate")
		}
		tlsConfig = &tls.Config{MinVersion: tls.VersionTLS12, RootCAs: roots}
	}
	var clientCertificateProvider neo4jauth.ClientCertificateProvider
	if params.ClientCertPath != "" || params.ClientKeyPath != "" {
		if params.ClientCertPath == "" || params.ClientKeyPath == "" {
			return nil, errors.New("both client certificate and client key are required")
		}
		provider, err := neo4jauth.NewStaticClientCertificateProvider(neo4jauth.ClientCertificate{
			CertFile: params.ClientCertPath,
			KeyFile:  params.ClientKeyPath,
		})
		if err != nil {
			return nil, fmt.Errorf("load Neo4j client certificate: %w", err)
		}
		clientCertificateProvider = provider
	}
	if tlsConfig == nil && clientCertificateProvider == nil {
		return nil, nil
	}
	return func(driverConfig *config.Config) {
		if tlsConfig != nil {
			driverConfig.TlsConfig = tlsConfig
		}
		if clientCertificateProvider != nil {
			driverConfig.ClientCertificateProvider = clientCertificateProvider
		}
	}, nil
}

func buildNeo4jURI(params connectParams) (string, error) {
	if value := strings.TrimSpace(params.ConnectionString); value != "" {

View on GitHub (pinned to c0390bff16)

Solutions

  1. Verify both ClientCertPath and ClientKeyPath point to existing, readable files on the host running the driver
  2. Confirm the key file matches the certificate (compare modulus/public key) and that both are valid PEM
  3. Check file permissions so the agent process user can read the key (keys are often 0600 root-owned)
  4. Regenerate or re-export the cert/key pair if the PEM data is malformed
  5. Print the wrapped underlying error (%w) from the log to see the exact cause (e.g. open ...: no such file or directory)

Example fix

// before
params.ClientCertPath = "certs/client.pem" // relative path, wrong cwd
// after
params.ClientCertPath = "/etc/neo4j/tls/client.pem"
params.ClientKeyPath  = "/etc/neo4j/tls/client.key" // absolute paths, verified readable
Defensive patterns

Strategy: validation

Validate before calling

for _, p := range []string{params.ClientCertPath, params.ClientKeyPath} {
    if fi, err := os.Stat(p); err != nil || fi.IsDir() {
        return fmt.Errorf("tls file missing or unreadable: %s", p)
    }
}
if _, err := os.ReadFile(params.ClientKeyPath); err != nil {
    return fmt.Errorf("key file not readable by this user: %w", err)
}

Type guard

func certFilesReadable(certPath, keyPath string) bool {
    for _, p := range []string{certPath, keyPath} {
        f, err := os.Open(p)
        if err != nil { return false }
        f.Close()
    }
    return true
}

Prevention

When it happens

Trigger: Driver is configured with ClientCertPath/ClientKeyPath pointing to files that do not exist, are unreadable (permissions), contain malformed PEM data, or where the private key does not correspond to the certificate. The error is produced inside openDriver -> neo4jTLSConfigurer before any connection is attempted.

Common situations: Deployment mounts the cert volume at a different path than the driver config expects; running the agent as a non-root user without read permission on the key file; rotating certs and pointing only one of cert/key at the new files; using an encrypted key without supplying the passphrase.

Understand the failure class

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/5e002816df9cf964. Report an issue: GitHub.