juicedata/juicefs · error
received encrypted text length is less than 3, the object is
Error message
received encrypted text length is less than 3, the object is corrupted
What it means
dataEncryptor.Decrypt expects ciphertext prefixed with a 3-byte header (2-byte encrypted key length + 1-byte nonce length). If the received buffer is shorter than 3 bytes the object cannot possibly be valid encrypted data, so it is reported as corrupted.
Source
Thrown at pkg/object/encrypt.go:260
}
headerSize := 3 + len(cipherkey) + len(nonce)
buf := make([]byte, headerSize+len(plaintext)+aead.Overhead())
buf[0] = byte(len(cipherkey) >> 8)
buf[1] = byte(len(cipherkey) & 0xFF)
buf[2] = byte(len(nonce))
p := buf[3:]
copy(p, cipherkey)
p = p[len(cipherkey):]
copy(p, nonce)
p = p[len(nonce):]
ciphertext := aead.Seal(p[:0], nonce, plaintext, nil)
return buf[:headerSize+len(ciphertext)], nil
}
func (e *dataEncryptor) Decrypt(ciphertext []byte) ([]byte, error) {
if len(ciphertext) < 3 {
return nil, fmt.Errorf("received encrypted text length is less than 3, the object is corrupted")
}
keyLen := int(ciphertext[0])<<8 + int(ciphertext[1])
nonceLen := int(ciphertext[2])
if 3+keyLen+nonceLen >= len(ciphertext) {
return nil, fmt.Errorf("malformed ciphertext: %d %d", keyLen, nonceLen)
}
ciphertext = ciphertext[3:]
cipherkey := ciphertext[:keyLen]
nonce := ciphertext[keyLen : keyLen+nonceLen]
ciphertext = ciphertext[keyLen+nonceLen:]
key, err := e.keyEncryptor.Decrypt(cipherkey)
if err != nil {
return nil, errors.New("decryt key: " + err.Error())
}
aead, err := e.aead(key)
if err != nil {
return nil, errView on GitHub (pinned to c9a67b23e8)
Solutions
- Verify the object was written with the same encryption settings; re-upload the object from a healthy replica with encryption enabled
- Check the object size in the object store; if < 3 bytes it is corrupt — restore from backup or delete and let the client re-upload
- Ensure 'juicefs sync' or garbage collection was not interrupted mid-copy; re-run the sync with --check-all
- Confirm you did not switch encrypt keys/algo after the data was written; the whole volume must use consistent encryption
Example fix
// before: mixing plain and encrypted writes to the same path
cfg.EncryptKeyPath = "" // some writes go unencrypted
// after: keep encryption enabled for all writes
key, _ := ParseRsaPrivateKeyFromPath("/keys/priv.pem", "")
store, _ := createStorage(..., key, "aes256gcm-rsa") Defensive patterns
Strategy: try-catch
Validate before calling
obj, _ := store.Head(key)
if obj.Size() < 3 { /* skip or restore: object cannot be valid encrypted data */ } Try / catch
plain, err := enc.Decrypt(ciphertext)
if err != nil && strings.Contains(err.Error(), "less than 3") {
// object corrupt/unencrypted: restore from replica or re-upload
} Prevention
- Never mix encrypted and unencrypted writes to the same volume/bucket prefix
- Use juicefs sync --check-all periodically to detect truncated objects
- Enable object-store versioning or backups for recovery
- Keep encryption settings immutable after volume format
When it happens
Trigger: Calling Read on an encrypted object whose stored content is empty or shorter than 3 bytes — e.g. the object was uploaded unencrypted, truncated, or written by a non-JuiceFS tool into the same bucket path.
Common situations: Reading a legacy/plain object with encryption enabled; bucket re-pointed or data partially synced; manual upload/overwrite of the object in object storage; interrupted write left a stub object.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- malformed ciphertext: %d %d
- Decrypt: %s
- Decrypt: truncated chunk header
- Decrypt: chunk data truncated: need %d, have %d
- read wrong data: expected %x, got %x
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/298fa6602fd7cfbb.
Report an issue: GitHub.