juicedata/juicefs · error

failed to parse PEM block containing the key

Error message

failed to parse PEM block containing the key

What it means

pem.Decode returned nil for the input bytes in ParsePrivateKeyFromPem, meaning they do not form a recognizable PEM block (missing BEGIN/END markers, corrupted base64, or wrong DER encoding). This is a validation guard rejecting malformed key material before any decryption is attempted.

Source

Thrown at pkg/object/encrypt.go:70

	}
	if passphrase != "" {
		var err error
		// nolint:staticcheck
		block, _ = x509.EncryptPEMBlock(rand.Reader, block.Type, buf, []byte(passphrase), x509.PEMCipherAES256)
		if err != nil {
			panic(err)
		}
	}
	privPEM := pem.EncodeToMemory(block)
	return string(privPEM)
}

var ErrKeyNeedPasswd = errors.New("passphrase is required to private key")

func ParsePrivateKeyFromPem(enc []byte, passphrase []byte) (any, error) {
	block, _ := pem.Decode(enc)
	if block == nil {
		return nil, errors.New("failed to parse PEM block containing the key")
	}

	buf := block.Bytes
	if len(passphrase) == 0 {
		// nolint:staticcheck
		if strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED") && x509.IsEncryptedPEMBlock(block) {
			return nil, ErrKeyNeedPasswd
		}
		if strings.Contains(block.Type, "ENCRYPTED") {
			return nil, ErrKeyNeedPasswd
		}
	} else {
		var err error
		// nolint:staticcheck
		buf, err = x509.DecryptPEMBlock(block, passphrase)
		if err != nil {
			if err == x509.IncorrectPasswordError {
				return nil, err

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Inspect the key file: it must contain '-----BEGIN RSA PRIVATE KEY-----' (or similar) PEM blocks; regenerate with juicefs format --encrypt-algo rsa-keygen if lost.
  2. Check the file path passed as the encrypt key resolves to the private key, not the public key or credentials file.
  3. Re-copy the key ensuring headers/footers and newlines are intact (no truncation, no HTML wrapping).
  4. If the key is DER-encoded, convert it: openssl rsa -in key.der -inform DER -out key.pem.

Example fix

// before (garbled file)
privKey, err := object.ParsePrivateKeyFromPem([]byte(read(cfg.Key)), []byte(os.Getenv("JFS_RSA_PASSPHRASE")))
// after (validate PEM presence first)
if !bytes.Contains(keyData, []byte("-----BEGIN")) {
    return nil, fmt.Errorf("%s is not a PEM-encoded private key", cfg.Key)
}
privKey, err := object.ParsePrivateKeyFromPem(keyData, []byte(os.Getenv("JFS_RSA_PASSPHRASE")))
Defensive patterns

Strategy: validation

Validate before calling

func isPEM(b []byte) bool {
    block, _ := pem.Decode(b)
    return block != nil
}
// before use:
if !isPEM(keyData) {
    return fmt.Errorf("encrypt key is not PEM-encoded")
}

Type guard

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

Try / catch

privKey, err := object.ParsePrivateKeyFromPem(enc, pass)
if err != nil {
    if errors.Is(err, object.ErrKeyNeedPasswd) { /* passphrase issue */ }
    return fmt.Errorf("invalid encrypt key file: %w", err)
}

Prevention

When it happens

Trigger: Passing an empty/garbled encrypt key file, a raw DER key without PEM armor, a file with whitespace/HTML or wrong content, or a path read that returned an error page/empty string to ParsePrivateKeyFromPem (via format, load, or open of an encrypted store).

Common situations: Misconfigured --encrypt-key pointing to the public key or to a text file; copy-paste that lost the BEGIN/END lines; cloud IAM cred file accidentally used as the key; truncated download.

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/366b874f22254b89. Report an issue: GitHub.