{"record":{"id":"d07c17c2b7fa3fe8","repo":"siyuan-note/siyuan","slug":"invalid-encrypted-asset-format","errorCode":null,"errorMessage":"invalid encrypted asset format","messagePattern":"invalid encrypted asset format","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":2303,"sourceCode":"\t\t\tencryptedAssetChunkAAD(aadPrefix, containerID, chunkIndex),\n\t\t)\n\t\tif encryptErr != nil {\n\t\t\treturn nil, encryptErr\n\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}","sourceCodeStart":2285,"sourceCodeEnd":2321,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/crypto.go#L2285-L2321","documentation":"decryptAssetMetadata validates that the ciphertext starts with the 8-byte header: the 4-byte magic 'SYAE' plus at least 8 total bytes to read the metadata length. This error means the byte slice is not a recognizable encrypted-asset container — wrong magic or too-short input.","triggerScenarios":"Decrypting (via DecryptAssetWithName / DecryptAssetToWriter / metadata readers) a blob shorter than 8 bytes or not beginning with bytes 'SYAE'; passing plaintext file content, a truncated/corrupted file, or data encrypted by a different scheme (e.g. whole-notebook ciphertext without the asset magic).","commonSituations":"Pointing asset decryption at a non-encrypted asset file; truncated download/sync leaving a partial container; version mismatch where an old file layout predates the SYAE magic; hand-edited or corrupted .sy-referenced assets.","solutions":["Verify the file is a genuine encrypted asset: first 4 bytes must be 'S','Y','A','E' (use model.IsEncryptedNotebookData as a pre-check)","Re-download or restore the asset from sync/history — the local copy is likely truncated or corrupted","Re-encrypt the original source with EncryptAsset instead of decrypting a non-encrypted file"],"exampleFix":"// before\nplain, name, err := model.DecryptAssetWithName(box, disk, dek, data)\n// after\nif len(data) < 8 || string(data[:4]) != \"SYAE\" {\n    return errors.New(\"not an encrypted asset container\")\n}\nplain, name, err := model.DecryptAssetWithName(box, disk, dek, data)","handlingStrategy":"type-guard","validationCode":"func isEncryptedAssetContainer(data []byte) bool {\n    return len(data) >= 8 && bytes.Equal(data[:4], []byte(\"SYAE\"))\n}","typeGuard":"func looksLikeEncryptedAsset(r io.Reader) (bool, error) {\n    head := make([]byte, 4)\n    if _, err := io.ReadFull(r, head); err != nil {\n        return false, err\n    }\n    if seeker, ok := r.(io.Seeker); ok { seeker.Seek(0, io.SeekStart) }\n    return bytes.Equal(head, []byte(\"SYAE\")), nil\n}","tryCatchPattern":"plain, name, err := model.DecryptAssetWithName(box, disk, dek, data)\nif err != nil && strings.Contains(err.Error(), \"invalid encrypted asset format\") {\n    return readUnencryptedAsset(data) // fall back to plain path\n}","preventionTips":["Use model.IsEncryptedNotebookData(data) to pick the encrypted vs plain read path before decrypting","Verify file sizes after sync/download to catch truncation early","Do not mix notebook-level ciphertext and asset-container bytes in the same storage field"],"tags":["encryption","corrupt-data","format-validation"],"backgroundTag":"invalid-argument-format","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"}