siyuan-note/siyuan · error

invalid encrypted asset plaintext chunk size

Error message

invalid encrypted asset plaintext chunk size

What it means

After decrypting a chunk, the code validates that the plaintext length equals the expected chunk size (full encryptedAssetChunkSize, or the remaining bytes for the final chunk). This error means decryption produced plaintext of the wrong length — strong evidence of tampering or AAD/context mismatch, since AES-GCM would normally fail authentication first. The chunk is zeroed before returning.

Source

Thrown at kernel/model/crypto.go:2476

		aad := encryptedAssetChunkAAD(aadPrefix, metadata.ContainerID, chunkIndex)
		if metadata.Spec == encryptedAssetLegacySpec {
			aad = []byte(fmt.Sprintf("%s:content:%d", aadPrefix, chunkIndex))
		}
		plainChunk, chunkErr := util.DecryptWithAAD(
			assetKey,
			encryptedChunk,
			aad,
		)
		if chunkErr != nil {
			return "", chunkErr
		}
		expectedSize := int64(encryptedAssetChunkSize)
		if remaining := metadata.Size - written; remaining < expectedSize {
			expectedSize = remaining
		}
		if int64(len(plainChunk)) != expectedSize {
			zeroAndClear(plainChunk)
			return "", errors.New("invalid encrypted asset plaintext chunk size")
		}
		n, writeErr := writer.Write(plainChunk)
		written += int64(n)
		zeroAndClear(plainChunk)
		if writeErr != nil {
			return "", writeErr
		}
		if n != len(plainChunk) {
			return "", io.ErrShortWrite
		}
	}
	var terminator uint32
	if err = binary.Read(reader, binary.BigEndian, &terminator); err != nil {
		return "", err
	}
	if terminator != 0 || written != metadata.Size {
		return "", errors.New("invalid encrypted asset content length")
	}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Treat the file as tampered or corrupt; restore from a verified backup
  2. Re-encrypt from the original plaintext if it still exists elsewhere
  3. Compare metadata.Size and the sum of chunk sizes against the file length to locate the inconsistent region
  4. Verify the file's integrity via sync history or the device it originated from
Defensive patterns

Strategy: try-catch

Try / catch

plain, err := model.DecryptAsset(box, disk, dek, ct)
if err != nil {
    if strings.Contains(err.Error(), "plaintext chunk size") {
        // treat file as tampered: quarantine and restore from backup
        return restoreFromBackup(disk)
    }
    return err
}

Prevention

When it happens

Trigger: In DecryptAssetToWriter's chunk loop, a decrypted plainChunk's length does not match metadata.Size - written (clamped to encryptedAssetChunkSize). Happens when the file's chunk boundaries were re-framed after encryption or metadata.Size does not match the actual content.

Common situations: A tool rewrote or re-chunked the encrypted file without updating metadata; corruption shifting bytes between chunks; an intentionally tampered ciphertext where GCM tags were also forged (extremely rare).

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 siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/0d70d528de01b619. Report an issue: GitHub.