{"record":{"id":"f4a4c76db0064e8d","repo":"juicedata/juicefs","slug":"get-certificate-error-certfile-s-keyfile-s-error","errorCode":null,"errorMessage":"get certificate error certFile:%s keyFile:%s error:%s","messagePattern":"get certificate error certFile:(.+?) keyFile:(.+?) error:(.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/redis.go","lineNumber":149,"sourceCode":"\tclientCache := clientCacheStr != \"false\" && clientCacheStr != \"\"\n\tclientCacheSize := query.getInt(\"client-cache-size\", \"client_cache_size\", 12800)\n\t// Default TTL to prevent reading stale cache for a long time when the connection fails.\n\tclientCacheExpiry := query.duration(\"client-cache-expire\", \"client_cache_expire\", time.Minute)\n\tclientCachePreload := query.getInt(\"client-cache-preload\", \"client_cache_preload\", 0) // may cause conflict\n\tu.RawQuery = values.Encode()\n\n\thosts := u.Host\n\topt, err := redis.ParseURL(u.String())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"redis parse %s: %s\", uri, err)\n\t}\n\tif opt.TLSConfig != nil {\n\t\topt.TLSConfig.ServerName = tlsServerName // use the host of each connection as ServerName\n\t\topt.TLSConfig.InsecureSkipVerify = skipVerify != \"\"\n\t\tif certFile != \"\" {\n\t\t\tcert, err := tls.LoadX509KeyPair(certFile, keyFile)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"get certificate error certFile:%s keyFile:%s error:%s\", certFile, keyFile, err)\n\t\t\t}\n\t\t\topt.TLSConfig.Certificates = []tls.Certificate{cert}\n\t\t}\n\t\tif caCertFile != \"\" {\n\t\t\tcaCert, err := os.ReadFile(caCertFile)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"read ca cert file error path:%s error:%s\", caCertFile, err)\n\t\t\t}\n\t\t\tcaCertPool := x509.NewCertPool()\n\t\t\tcaCertPool.AppendCertsFromPEM(caCert)\n\t\t\topt.TLSConfig.RootCAs = caCertPool\n\t\t}\n\t}\n\tif opt.Password == \"\" {\n\t\topt.Password = os.Getenv(\"REDIS_PASSWORD\")\n\t}\n\tif opt.Password == \"\" {\n\t\topt.Password = os.Getenv(\"META_PASSWORD\")","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/redis.go#L131-L167","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify both cert-file and key-file paths exist and are readable by the JuiceFS process (ls/permissions inside the same container/host).","Check the files are valid PEM: `openssl x509 -in cert.crt` and `openssl rsa -in cert.key -check`.","Confirm the key matches the certificate: compare `openssl x509 -noout -modulus` with `openssl rsa -noout -modulus`.","If mutual TLS is not required, remove cert-file/key-file from the URL and keep only ca-cert-file."],"exampleFix":"// before\njuicefs mount \"rediss://redis:6379?cert-file=/etc/jfs/client.crt&key-file=/etc/jfs/client.key\" /jfs\n// error: get certificate error certFile:/etc/jfs/client.crt keyFile:/etc/jfs/client.key error: open ...: no such file or directory\n// after\nmount the secrets into the container first, e.g. docker run -v $PWD/certs:/etc/jfs ... then the same mount command succeeds","handlingStrategy":"validation","validationCode":"// verify cert/key before mounting\nfor _, f := range []string{certFile, keyFile} {\n\tif fi, err := os.Stat(f); err != nil || fi.IsDir() { return fmt.Errorf(\"TLS file %q missing\", f) }\n}\nif _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil { return fmt.Errorf(\"bad cert/key pair: %w\", err) }","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"get certificate error\") {\n\treturn fmt.Errorf(\"verify cert-file/key-file exist, are valid PEM, and match: %w\", err)\n}","preventionTips":["Volume-mount TLS secrets into containers before mounting the volume.","Validate cert/key pairs with openssl during deployment pipelines.","Set readable file permissions and check after secret rotation.","Keep CA, cert, and key fields in the URL distinct to avoid mixing them up."],"tags":["redis","tls","certificate","config"],"backgroundTag":"file-not-found","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}