juicedata/juicefs · error

parse private key: %s

Error message

parse private key: %s

What it means

When loading an encrypted metadata backup, `juicefs load` parses the RSA private key from a PEM file (or KMS) via object.ParsePrivateKeyFromPem to build a decryptor. If the PEM data cannot be parsed as a private key — and it is not merely a passphrase-protected key — the command aborts with `parse private key: <underlying error>`. This means the key material itself is unreadable, wrong, or in an unsupported format.

Source

Thrown at cmd/load.go:117

		return err
	}
	if r.encryptR != r.compressR {
		return r.encryptR.Close()
	}
	return nil
}

func open(src string, key string, algo string) (io.ReadCloser, error) {
	var r io.ReadCloser
	var ioErr error
	var fp io.ReadCloser
	if key != "" {
		privKey, err := object.ParsePrivateKeyFromPem([]byte(loadEncrypt(key)), []byte(os.Getenv("JFS_RSA_PASSPHRASE")))
		if err != nil {
			if errors.Is(err, object.ErrKeyNeedPasswd) {
				return nil, fmt.Errorf("%w: please set the 'JFS_RSA_PASSPHRASE' environment variable", err)
			}
			return nil, fmt.Errorf("parse private key: %s", err)
		}
		encryptor, err := object.NewDataEncryptor(object.NewKeyEncryptor(privKey), algo)
		if err != nil {
			return nil, err
		}
		if _, err := os.Stat(src); err != nil {
			return nil, fmt.Errorf("failed to stat %s: %s", src, err)
		}
		var srcAbsPath string
		srcAbsPath, err = filepath.Abs(src)
		if err != nil {
			return nil, fmt.Errorf("failed to get absolute path of %s: %s", src, err)
		}
		fileBlob, err := object.CreateStorage("file", strings.TrimSuffix(src, filepath.Base(srcAbsPath)), "", "", "")
		if err != nil {
			return nil, err
		}
		blob := object.NewEncrypted(fileBlob, encryptor)

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Inspect the key file with `openssl pkey -in <keyfile> -noout -text` to confirm it is a valid RSA private key
  2. Re-export the original RSA private key used at `juicefs format` time and save it as a PEM file
  3. Verify you passed the key path/URI to the correct flag and that the file was downloaded completely (check size)
  4. If the key is passphrase-protected, set JFS_RSA_PASSPHRASE so the correct ErrKeyNeedPasswd branch is taken instead

Example fix

// before
juicefs load --encrypt-secret ./cert.pem sqlite3://test.db /tmp/backup.json
// after
juicefs load --encrypt-secret ./private.key sqlite3://test.db /tmp/backup.json  # private.key must be the RSA private key PEM
Defensive patterns

Strategy: validation

Validate before calling

if !strings.Contains(pemBytes, "PRIVATE KEY") {
    return fmt.Errorf("%s is not a private key PEM", keyPath)
}
out, err := exec.Command("openssl", "pkey", "-in", keyPath, "-noout").CombinedOutput()
if err != nil { return fmt.Errorf("invalid key: %s", out) }

Try / catch

if err := runLoad(); err != nil {
    if strings.Contains(err.Error(), "parse private key") {
        log.Fatalf("check key file and JFS_RSA_PASSPHRASE: %v", err)
    }
}

Prevention

When it happens

Trigger: Running `juicefs load`/`convert` with --encrypt-secret (the `key` flag) pointing to a PEM file that is corrupt, truncated, not a PEM block, contains a public key instead of a private key, or is in an unsupported format (e.g. PKCS1 vs PKCS8 issues handled incorrectly). Also triggered when the key was re-uploaded/re-exported incorrectly from a KMS.

Common situations: Copying the key file and accidentally truncating it; exporting a certificate or public key instead of the RSA private key; passing a path to a config file instead of the key; the PEM file being empty or containing whitespace/HTML from a web console copy-paste; JFS_RSA_PASSPHRASE set but the key is simply invalid.

Related errors


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