{"record":{"id":"9af0c1f04c1ce163","repo":"siyuan-note/siyuan","slug":"invalid-encrypted-asset-metadata-size","errorCode":null,"errorMessage":"invalid encrypted asset metadata size","messagePattern":"invalid encrypted asset metadata size","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":2307,"sourceCode":"\t\t}\n\t\tif err = binary.Write(ret, binary.BigEndian, uint32(len(encryptedChunk))); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tret.Write(encryptedChunk)\n\t}\n\tif err = binary.Write(ret, binary.BigEndian, uint32(0)); err != nil {\n\t\treturn nil, err\n\t}\n\treturn ret.Bytes(), nil\n}\n\nfunc decryptAssetMetadata(boxID, diskName string, dek, ciphertext []byte) (metadata *encryptedAssetMetadata, contentOffset int, err error) {\n\tif len(ciphertext) < 8 || !bytes.Equal(ciphertext[:4], encryptedAssetMagic) {\n\t\treturn nil, 0, errors.New(\"invalid encrypted asset format\")\n\t}\n\tmetadataSize := int(binary.BigEndian.Uint32(ciphertext[4:8]))\n\tif metadataSize < 1 || metadataSize > encryptedAssetMetadataMaxSize || 8+metadataSize+4 > len(ciphertext) {\n\t\treturn nil, 0, errors.New(\"invalid encrypted asset metadata size\")\n\t}\n\tassetKey := util.DeriveSubKey(dek, \"siyuan/asset\")\n\tdefer zeroAndClear(assetKey)\n\taadPrefix := \"siyuan:asset:\" + boxID + \":assets/\" + diskName\n\tplainMetadata, decryptErr := util.DecryptWithAAD(assetKey, ciphertext[8:8+metadataSize], []byte(aadPrefix+\":metadata\"))\n\tif decryptErr != nil {\n\t\treturn nil, 0, decryptErr\n\t}\n\tdefer zeroAndClear(plainMetadata)\n\tif metadata, err = parseEncryptedAssetMetadata(plainMetadata); err != nil {\n\t\treturn nil, 0, err\n\t}\n\treturn metadata, 8 + metadataSize, nil\n}\n\n// encryptedAssetChunkAAD 将分块绑定到本次写入的容器，阻止同名资源的不同版本互换分块。\nfunc encryptedAssetChunkAAD(prefix string, containerID []byte, index uint64) []byte {\n\treturn []byte(fmt.Sprintf(\"%s:content:v%d:%x:%d\", prefix, encryptedAssetSpec, containerID, index))","sourceCodeStart":2289,"sourceCodeEnd":2325,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/crypto.go#L2289-L2325","documentation":"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.","triggerScenarios":"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.","commonSituations":"Interrupted sync or download leaving a truncated container; disk corruption flipping bytes in the length prefix; attempting to decrypt a file that mixes formats.","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"],"exampleFix":"// before\nplain, name, err := model.DecryptAssetWithName(box, disk, dek, data)\n// after\nif len(data) >= 8 {\n    sz := int(binary.BigEndian.Uint32(data[4:8]))\n    if sz <= 0 || sz > 1024*1024 || 8+sz+4 > len(data) {\n        return errors.New(\"encrypted asset truncated or corrupt\")\n    }\n}\nplain, name, err := model.DecryptAssetWithName(box, disk, dek, data)","handlingStrategy":"validation","validationCode":"func containerHeaderSane(data []byte) bool {\n    if len(data) < 8 { return false }\n    sz := int(binary.BigEndian.Uint32(data[4:8]))\n    return sz >= 1 && sz <= 1<<20 && 8+sz+4 <= len(data)\n}","typeGuard":null,"tryCatchPattern":"plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)\nif err != nil && strings.Contains(err.Error(), \"invalid encrypted asset metadata size\") {\n    return restoreAssetFromHistory(box, disk)\n}","preventionTips":["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"],"tags":["encryption","corrupt-data","format-validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}