{"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":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":2265,"sourceCode":"\t\t\t[]byte(fmt.Sprintf(\"%s:content:%d\", aadPrefix, 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\tmetadata = &encryptedAssetMetadata{}\n\tif err = json.Unmarshal(plainMetadata, metadata); err != nil {\n\t\treturn nil, 0, err\n\t}\n\tif metadata.OriginalName == \"\" || metadata.OriginalName == \".\" ||\n\t\tfilepath.Base(metadata.OriginalName) != metadata.OriginalName || strings.ContainsAny(metadata.OriginalName, `/\\`) {","sourceCodeStart":2247,"sourceCodeEnd":2283,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/crypto.go#L2247-L2283","documentation":"Thrown by decryptAssetMetadata when the ciphertext is shorter than 8 bytes or does not begin with the 4-byte magic 'SYAE' (0x53 0x59 0x41 0x45). This means the input is not a SiYuan encrypted asset container at all — it is either a plaintext asset, a truncated file, or a foreign format.","triggerScenarios":"DecryptAsset / DecryptAssetWithName / copyAssetDecryptIfEncrypted is invoked on a file that is not in the SYAE encrypted format. Happens when IsEncryptedBox(boxID) returned true but the specific asset file on disk was never encrypted (e.g., written before encryption was enabled, or placed manually).","commonSituations":"User enabled encryption on an existing notebook, but some assets predate the encryption migration and remain as plaintext files. File was partially downloaded/restored from a corrupted backup. A sync conflict left a plaintext copy in an encrypted notebook's assets directory.","solutions":["Check whether the file starts with the SYAE magic bytes before attempting decryption; if not, treat it as plaintext.","Re-run the encryption migration for the notebook to convert any remaining plaintext assets.","Restore the asset from a known-good backup if it is truncated or corrupted."],"exampleFix":"// before\nplain, err := DecryptAsset(boxID, diskName, dek, raw)\n// after\nif len(raw) < 8 || !bytes.Equal(raw[:4], encryptedAssetMagic) {\n    // not an encrypted asset — handle as plaintext\n    plain = raw\n} else {\n    plain, err = DecryptAsset(boxID, diskName, dek, raw)\n}","handlingStrategy":"type-guard","validationCode":"// Check for SYAE magic before decrypting\nvar encryptedAssetMagic = []byte{'S', 'Y', 'A', 'E'}\nif len(raw) >= 4 && bytes.Equal(raw[:4], encryptedAssetMagic) {\n    plain, err = DecryptAsset(boxID, diskName, dek, raw)\n} else {\n    plain = raw // plaintext asset\n}","typeGuard":"func isEncryptedAsset(data []byte) bool {\n    magic := []byte{'S', 'Y', 'A', 'E'}\n    return len(data) >= 8 && bytes.Equal(data[:4], magic)\n}","tryCatchPattern":null,"preventionTips":["Use IsCiphertext or check the SYAE magic before calling DecryptAsset.","After enabling encryption on an existing notebook, run the migration to convert all plaintext assets.","Periodically validate that all assets in an encrypted notebook's directory are in SYAE format."],"tags":["encryption","asset","format-validation","corruption","crypto"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}