juicedata/juicefs · error

load %s key: %w

Error message

load %s key: %w

What it means

wrapSyncEncryptedStore loads the RSA private key used for client-side encryption during `juicefs sync` (for --encrypt-rsa-key / --enc-key) via object.ParseRsaPrivateKeyFromPath. This error wraps any parse failure other than the 'key needs a passphrase' case — unreadable file, wrong format (not PEM/PKCS), or corrupted key data.

Source

Thrown at cmd/sync.go:505

}

func isS3PathType(endpoint string) bool {
	//localhost[:8080] 127.0.0.1[:8080]  s3.ap-southeast-1.amazonaws.com[:8080] s3-ap-southeast-1.amazonaws.com[:8080]
	pattern := `^((localhost)|(s3[.-].*\.amazonaws\.com)|((1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.((1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.){2}(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)))?(:\d*)?$`
	return regexp.MustCompile(pattern).MatchString(endpoint)
}

func wrapSyncEncryptedStore(store object.ObjectStorage, keyPath, passphraseEnv, mode, algo string) (object.ObjectStorage, error) {
	if keyPath == "" {
		return store, nil
	}

	privKey, err := object.ParseRsaPrivateKeyFromPath(keyPath, os.Getenv(passphraseEnv))
	if err != nil {
		if errors.Is(err, object.ErrKeyNeedPasswd) {
			logger.Fatalf("%s key is password protected, please set %s environment variable", mode, passphraseEnv)
		}
		return nil, fmt.Errorf("load %s key: %w", mode, err)
	}

	encryptor, err := object.NewDataEncryptor(object.NewKeyEncryptor(privKey), algo)
	if err != nil {
		return nil, fmt.Errorf("create %sor: %w", mode, err)
	}

	return object.NewChunkedEncrypted(store, encryptor), nil
}

func loadClusterWorkerConfig(r io.Reader) (string, string, error) {
	src, dst, env, err := sync.ReadClusterWorkerConfig(r)
	if err != nil {
		return "", "", err
	}
	for key, value := range env {
		if err := os.Setenv(key, value); err != nil {
			return "", "", fmt.Errorf("set worker environment %q: %s", key, err)

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Verify the key file exists and is readable: `ls -l <key>` / `openssl rsa -in <key> -check -noout`
  2. Regenerate the key in PEM PKCS form if the format is unsupported: `openssl genrsa -out mykey.pem 2048`
  3. If the key is actually passphrase-protected, set the passphrase environment variable (e.g. JFS_RSA_PASSPHRASE) — that produces a clearer fatal message instead
  4. Point --encrypt-rsa-key at a private key, not a public key or certificate

Example fix

// before
juicefs sync --encrypt-rsa-key id_rsa.pub src dst
// load encrypt-algo key: ... (public key, not parseable)
// after
juicefs sync --encrypt-rsa-key id_rsa src dst  # private PEM key
Defensive patterns

Strategy: validation

Validate before calling

key, err := os.ReadFile(keyPath)
if err != nil {
	return fmt.Errorf("cannot read encryption key %s: %w", keyPath, err)
}
if !strings.Contains(string(key), "PRIVATE KEY") {
	return fmt.Errorf("%s does not look like a PEM private key", keyPath)
}

Type guard

null

Try / catch

if err != nil {
	if strings.HasPrefix(err.Error(), "load ") && strings.Contains(err.Error(), "key:") {
		// key file unreadable or wrong format; prompt user to regenerate
	}
	return err
}

Prevention

When it happens

Trigger: doSync invoked with an encryption key path (--encrypt-rsa-key) pointing to a file that does not exist, is not readable, or contains a key in an unsupported format (e.g. raw DER, ssh-ed25519 key, or a public key instead of a private RSA key). The passphrase case is handled separately with logger.Fatalf, so it does not produce this error.

Common situations: Typo in the key file path; key generated with a tool producing non-PKCS1/PKCS8 output; passing an SSH public key (.pub); file permissions blocking the sync user; key file truncated by a failed transfer.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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