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, err

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Verify the object was written with the same encryption settings; re-upload the object from a healthy replica with encryption enabled
  2. 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
  3. Ensure 'juicefs sync' or garbage collection was not interrupted mid-copy; re-run the sync with --check-all
  4. 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

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


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