juicedata/juicefs · error

parse private key: %s

Error message

parse private key: %s

What it means

The RSA private key configured as --encrypt-key could not be parsed. This is the fallback branch when the failure is not 'key needs a passphrase' — the PEM content is malformed, the wrong format, the passphrase is wrong, or decoding fails.

Source

Thrown at cmd/format.go:295

	}

	if format.Shards > 1 {
		blob, err = object.NewSharded(strings.ToLower(format.Storage), format.Bucket, format.AccessKey, format.SecretKey, format.SessionToken, format.Shards)
	} else {
		blob, err = object.CreateStorage(strings.ToLower(format.Storage), format.Bucket, format.AccessKey, format.SecretKey, format.SessionToken)
	}
	if err != nil {
		return nil, err
	}
	blob = object.WithPrefix(blob, format.Name+"/")
	initStorageTiers(blob, format.Tiers)
	if format.EncryptKey != "" {
		privKey, err := object.ParsePrivateKeyFromPem([]byte(format.EncryptKey), []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), format.EncryptAlgo)
		if err != nil {
			return nil, err
		}
		blob = object.NewEncrypted(blob, encryptor)
	}
	return blob, nil
}

func initStorageTiers(storage object.ObjectStorage, tiers object.Tiers) {
	if tierStorage, ok := storage.(object.SupportTier); ok {
		if err := tierStorage.InitTiers(tiers); err != nil && hasConfiguredTiers(tiers) {
			logger.Warnf("Set storage tier: %s", err)
		}
	}
}

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Validate the key locally: `openssl rsa -in key.pem -check -noout` (or `openssl pkey`)
  2. Confirm you are passing the private key, not the certificate or public key
  3. Verify JFS_RSA_PASSPHRASE matches the passphrase used at key-generation time
  4. Re-export the key in a standard format: `openssl pkcs8 -topk8 -in key.pem -out key8.pem` and retry

Example fix

// before
--encrypt-key cert.pem   // a certificate, not a key
// after
--encrypt-key private-key.pem  // validated with openssl rsa -check
Defensive patterns

Strategy: validation

Validate before calling

keyData, err := os.ReadFile(keyPath)
if err != nil { return err }
if !bytes.Contains(keyData, []byte("-----BEGIN")) || !bytes.Contains(keyData, []byte("PRIVATE KEY-----")) {
    return fmt.Errorf("%s is not a PEM private key", keyPath)
}

Type guard

func isPEMPrivateKey(data []byte) bool {
    block, _ := pem.Decode(data)
    return block != nil && strings.HasSuffix(block.Type, "PRIVATE KEY")
}

Try / catch

_, err := createStorage(...)
if err != nil && strings.HasPrefix(err.Error(), "parse private key:") {
    // key file invalid or wrong passphrase; re-validate with openssl
}

Prevention

When it happens

Trigger: --encrypt-key points to a file that is not a valid PEM private key (a certificate, a public key, corrupted content), or the key is encrypted and the JFS_RSA_PASSPHRASE provided is incorrect, or the key uses an unsupported algorithm/format (e.g. PKCS#1 vs PKCS#8 mismatches handled differently by the parser).

Common situations: Typo passing a public key or cert as the encrypt key; wrong passphrase after rotation; key file truncated during copy; generating keys with tools producing formats the Go parser rejects.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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