{"record":{"id":"3d92cd1b44ae47b2","repo":"juicedata/juicefs","slug":"decrypt-s","errorCode":null,"errorMessage":"Decrypt: %s","messagePattern":"Decrypt: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/object/encrypt.go","lineNumber":338,"sourceCode":"}\n\nfunc (e *encrypted) String() string {\n\treturn fmt.Sprintf(\"%s(encrypted)\", e.ObjectStorage)\n}\n\nfunc (e *encrypted) Get(ctx context.Context, key string, off, limit int64, getters ...AttrGetter) (io.ReadCloser, error) {\n\tr, err := e.ObjectStorage.Get(ctx, key, 0, -1, getters...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer r.Close()\n\tciphertext, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tplain, err := e.enc.Decrypt(ciphertext)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Decrypt: %s\", err)\n\t}\n\tl := int64(len(plain))\n\tif off > l {\n\t\toff = l\n\t}\n\tif limit == -1 || off+limit > l {\n\t\tlimit = l - off\n\t}\n\tdata := plain[off : off+limit]\n\treturn io.NopCloser(bytes.NewBuffer(data)), nil\n}\n\nfunc (e *encrypted) Put(ctx context.Context, key string, in io.Reader, getters ...AttrGetter) error {\n\tplain, err := io.ReadAll(in)\n\tif err != nil {\n\t\treturn err\n\t}\n\tciphertext, err := e.enc.Encrypt(plain)","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/object/encrypt.go#L320-L356","documentation":"EncryptedObjectStorage.Get downloads the whole object and hands it to the underlying encryptor's Decrypt. Any decryption failure — bad header, corrupted bytes, wrong key — is wrapped as 'Decrypt: %s' before returning to the VFS layer.","triggerScenarios":"Calling Get on an encrypted object when the ciphertext fails dataEncryptor.Decrypt: wrong RSA private key configured, corrupted/truncated object, or object written without encryption.","commonSituations":"Volume re-mounted with a different encrypt key than the one used at format time; object store contents restored partially from backup; mixing encrypted and unencrypted data in one bucket.","solutions":["Mount with the original RSA private key used when the volume was formatted (encrypt-keys option)","Inspect the wrapped error text: 'less than 3' or 'malformed ciphertext' indicate corrupt objects — restore from backup/sync source","Re-sync data from a healthy source with juicefs sync using identical encryption settings","If the volume was formatted without encryption but read with one (or vice versa), align mount config with format config"],"exampleFix":"// before\njuicefs mount --encrypt-key /keys/newkey.pem redis://host db /mnt\n// after: use the original format-time key\njuicefs mount --encrypt-key /keys/original-priv.pem redis://host db /mnt","handlingStrategy":"try-catch","validationCode":"// compare format metadata vs mount config\n// juicefs config META-URL | grep encrypt  — ensure key/algo match before Get","typeGuard":null,"tryCatchPattern":"data, err := encStore.Get(ctx, key, off, size)\nif err != nil && strings.HasPrefix(err.Error(), \"Decrypt:\") {\n\t// wrong key or corrupt object: remount with original key / restore object\n}","preventionTips":["Keep the format-time RSA private key safely archived; mount always with it","Document encryption settings alongside volume credentials","Test decryption (read a canary file) right after mounting","Use backup/restore procedures that preserve object bytes exactly"],"tags":["crypto","decrypt","object-storage","key-mismatch"],"backgroundTag":"invalid-argument-value","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"}