siyuan-note/siyuan · error
invalid encrypted asset metadata size
Error message
invalid encrypted asset metadata size
What it means
After the magic check, decryptAssetMetadata reads the big-endian uint32 metadata length at bytes 4..8 and requires it to be >=1, <= encryptedAssetMetadataMaxSize (1 MiB), and to fit within the ciphertext (8+size+4 <= len). This error means the length field is zero, exceeds the cap, or the container is truncated before the metadata (and trailing 4 bytes) it declares.
Solutions
- Restore the asset from sync history or backup — a truncated/corrupted container cannot be repaired in place
- Re-encrypt from the original source if available
- Validate the container with model.IsEncryptedNotebookData and a length sanity check before calling decrypt paths
Example fix
// before
plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)
// after
if len(data) >= 8 {
sz := int(binary.BigEndian.Uint32(data[4:8]))
if sz <= 0 || sz > 1024*1024 || 8+sz+4 > len(data) {
return errors.New("encrypted asset truncated or corrupt")
}
}
plain, name, err := model.DecryptAssetWithName(box, disk, dek, data) Defensive patterns
Strategy: validation
Validate before calling
func containerHeaderSane(data []byte) bool {
if len(data) < 8 { return false }
sz := int(binary.BigEndian.Uint32(data[4:8]))
return sz >= 1 && sz <= 1<<20 && 8+sz+4 <= len(data)
} Try / catch
plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)
if err != nil && strings.Contains(err.Error(), "invalid encrypted asset metadata size") {
return restoreAssetFromHistory(box, disk)
} Prevention
- Compare synced file sizes against the size recorded in the document to detect truncation
- Never hand-edit encrypted asset files; length-prefix corruption is unrecoverable without a backup
- Keep sync history enabled so truncated containers can be rolled back
When it happens
Trigger: Decrypting a container whose header was corrupted (length overwritten), a file truncated mid-metadata, or a malicious/crafted file claiming an absurd metadata size; reading a partially synced asset.
Common situations: Interrupted sync or download leaving a truncated container; disk corruption flipping bytes in the length prefix; attempting to decrypt a file that mixes formats.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- invalid encrypted asset format
- invalid encrypted asset chunk count
- invalid encrypted asset content metadata
- invalid encrypted envelope nonce length
- 26
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/9af0c1f04c1ce163.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/crypto.go:2307
}
if err = binary.Write(ret, binary.BigEndian, uint32(len(encryptedChunk))); err != nil {
return nil, err
}
ret.Write(encryptedChunk)
}
if err = binary.Write(ret, binary.BigEndian, uint32(0)); err != nil {
return nil, err
}
return ret.Bytes(), nil
}
func decryptAssetMetadata(boxID, diskName string, dek, ciphertext []byte) (metadata *encryptedAssetMetadata, contentOffset int, err error) {
if len(ciphertext) < 8 || !bytes.Equal(ciphertext[:4], encryptedAssetMagic) {
return nil, 0, errors.New("invalid encrypted asset format")
}
metadataSize := int(binary.BigEndian.Uint32(ciphertext[4:8]))
if metadataSize < 1 || metadataSize > encryptedAssetMetadataMaxSize || 8+metadataSize+4 > len(ciphertext) {
return nil, 0, errors.New("invalid encrypted asset metadata size")
}
assetKey := util.DeriveSubKey(dek, "siyuan/asset")
defer zeroAndClear(assetKey)
aadPrefix := "siyuan:asset:" + boxID + ":assets/" + diskName
plainMetadata, decryptErr := util.DecryptWithAAD(assetKey, ciphertext[8:8+metadataSize], []byte(aadPrefix+":metadata"))
if decryptErr != nil {
return nil, 0, decryptErr
}
defer zeroAndClear(plainMetadata)
if metadata, err = parseEncryptedAssetMetadata(plainMetadata); err != nil {
return nil, 0, err
}
return metadata, 8 + metadataSize, nil
}
// encryptedAssetChunkAAD 将分块绑定到本次写入的容器,阻止同名资源的不同版本互换分块。
func encryptedAssetChunkAAD(prefix string, containerID []byte, index uint64) []byte {
return []byte(fmt.Sprintf("%s:content:v%d:%x:%d", prefix, encryptedAssetSpec, containerID, index))View on GitHub (pinned to 9f775e8a12)