juicedata/juicefs · error

get certificate error certFile:%s keyFile:%s error:%s

Error message

get certificate error certFile:%s keyFile:%s error:%s

What it means

When the redis URL uses TLS (`rediss://`) and client certificate authentication is configured, newRedisMeta loads the client cert/key pair with tls.LoadX509KeyPair (pkg/meta/redis.go:145-150). If the certificate or key file cannot be read or parsed (missing file, bad PEM, key/cert mismatch), construction fails with this message naming both file paths and the underlying error.

Source

Thrown at pkg/meta/redis.go:149

	clientCache := clientCacheStr != "false" && clientCacheStr != ""
	clientCacheSize := query.getInt("client-cache-size", "client_cache_size", 12800)
	// Default TTL to prevent reading stale cache for a long time when the connection fails.
	clientCacheExpiry := query.duration("client-cache-expire", "client_cache_expire", time.Minute)
	clientCachePreload := query.getInt("client-cache-preload", "client_cache_preload", 0) // may cause conflict
	u.RawQuery = values.Encode()

	hosts := u.Host
	opt, err := redis.ParseURL(u.String())
	if err != nil {
		return nil, fmt.Errorf("redis parse %s: %s", uri, err)
	}
	if opt.TLSConfig != nil {
		opt.TLSConfig.ServerName = tlsServerName // use the host of each connection as ServerName
		opt.TLSConfig.InsecureSkipVerify = skipVerify != ""
		if certFile != "" {
			cert, err := tls.LoadX509KeyPair(certFile, keyFile)
			if err != nil {
				return nil, fmt.Errorf("get certificate error certFile:%s keyFile:%s error:%s", certFile, keyFile, err)
			}
			opt.TLSConfig.Certificates = []tls.Certificate{cert}
		}
		if caCertFile != "" {
			caCert, err := os.ReadFile(caCertFile)
			if err != nil {
				return nil, fmt.Errorf("read ca cert file error path:%s error:%s", caCertFile, err)
			}
			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(caCert)
			opt.TLSConfig.RootCAs = caCertPool
		}
	}
	if opt.Password == "" {
		opt.Password = os.Getenv("REDIS_PASSWORD")
	}
	if opt.Password == "" {
		opt.Password = os.Getenv("META_PASSWORD")

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Verify both cert-file and key-file paths exist and are readable by the JuiceFS process (ls/permissions inside the same container/host).
  2. Check the files are valid PEM: `openssl x509 -in cert.crt` and `openssl rsa -in cert.key -check`.
  3. Confirm the key matches the certificate: compare `openssl x509 -noout -modulus` with `openssl rsa -noout -modulus`.
  4. If mutual TLS is not required, remove cert-file/key-file from the URL and keep only ca-cert-file.

Example fix

// before
juicefs mount "rediss://redis:6379?cert-file=/etc/jfs/client.crt&key-file=/etc/jfs/client.key" /jfs
// error: get certificate error certFile:/etc/jfs/client.crt keyFile:/etc/jfs/client.key error: open ...: no such file or directory
// after
mount the secrets into the container first, e.g. docker run -v $PWD/certs:/etc/jfs ... then the same mount command succeeds
Defensive patterns

Strategy: validation

Validate before calling

// verify cert/key before mounting
for _, f := range []string{certFile, keyFile} {
	if fi, err := os.Stat(f); err != nil || fi.IsDir() { return fmt.Errorf("TLS file %q missing", f) }
}
if _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil { return fmt.Errorf("bad cert/key pair: %w", err) }

Try / catch

if err != nil && strings.Contains(err.Error(), "get certificate error") {
	return fmt.Errorf("verify cert-file/key-file exist, are valid PEM, and match: %w", err)
}

Prevention

When it happens

Trigger: Setting `?cert-file=/path/cert.crt&key-file=/path/cert.key` on a rediss:// URL where either file does not exist, is unreadable, is not valid PEM, or the private key does not match the certificate.

Common situations: Mounting from a container where the cert files were not volume-mounted; TLS secrets rotated/deleted; passing the CA file paths in the cert/key fields by mistake; generating certs with mismatched key pairs.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/f4a4c76db0064e8d. Report an issue: GitHub.