{"record":{"id":"3de91918eb4b245f","repo":"siyuan-note/siyuan","slug":"invalid-encrypted-asset-content-length","errorCode":null,"errorMessage":"invalid encrypted asset content length","messagePattern":"invalid encrypted asset content length","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":2493,"sourceCode":"\t\t\tzeroAndClear(plainChunk)\n\t\t\treturn \"\", errors.New(\"invalid encrypted asset plaintext chunk size\")\n\t\t}\n\t\tn, writeErr := writer.Write(plainChunk)\n\t\twritten += int64(n)\n\t\tzeroAndClear(plainChunk)\n\t\tif writeErr != nil {\n\t\t\treturn \"\", writeErr\n\t\t}\n\t\tif n != len(plainChunk) {\n\t\t\treturn \"\", io.ErrShortWrite\n\t\t}\n\t}\n\tvar terminator uint32\n\tif err = binary.Read(reader, binary.BigEndian, &terminator); err != nil {\n\t\treturn \"\", err\n\t}\n\tif terminator != 0 || written != metadata.Size {\n\t\treturn \"\", errors.New(\"invalid encrypted asset content length\")\n\t}\n\tvar trailing [1]byte\n\tif _, trailingErr := io.ReadFull(reader, trailing[:]); trailingErr != io.EOF {\n\t\treturn \"\", errors.New(\"invalid trailing encrypted asset data\")\n\t}\n\treturn metadata.OriginalName, nil\n}\n\n// DecryptAsset 对应解密。\nfunc DecryptAsset(boxID, diskName string, dek, ciphertext []byte) ([]byte, error) {\n\tplaintext, _, err := DecryptAssetWithName(boxID, diskName, dek, ciphertext)\n\treturn plaintext, err\n}\n\n// notebookCryptoBackupPath 返回加密笔记本的独立 BoxCrypt 备份路径。\n// 该文件在主 conf.json 丢失时用作\"此笔记本是加密笔记本\"的标识和降级恢复源。\n// 与全局 NotebookCrypto 备份（<DataDir>/.siyuan/data-crypto-backup.json）配合使用，\n// 全局备份存 MasterSalt/KEKVerifier，per-notebook 备份存 WrappedDEK/WrapNonce。","sourceCodeStart":2475,"sourceCodeEnd":2511,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/crypto.go#L2475-L2511","documentation":"After all chunks are written, the reader must produce a uint32 terminator of 0 and the total bytes written must equal metadata.Size. This error means the stream ended early/late or the trailer is non-zero, so the decrypted content length does not match the declared size. The output is incomplete and must not be trusted.","triggerScenarios":"DecryptAssetToWriter finishes all metadata.Chunks chunks, then reads the trailer: terminator != 0 or written != metadata.Size — caused by truncated files, extra/missing chunks, or metadata whose Size field disagrees with the chunk data.","commonSituations":"An interrupted upload/download producing a short file; a file that gained or lost bytes in transfer; metadata edited externally with a wrong Size value.","solutions":["Re-download or restore the asset; the file is incomplete or inconsistent","Check the encrypted file's total size against header + metadata + chunks + trailer to find where it diverges","If the source plaintext exists, re-encrypt it with the current version","Use sync history/versioning in SiYuan to recover a complete copy"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"w, err := model.DecryptAssetToWriter(box, disk, dek, f, out)\nif err != nil {\n    if strings.Contains(err.Error(), \"content length\") {\n        os.Remove(outPath) // discard incomplete output\n        return restoreFromBackup(disk)\n    }\n    return err\n}","preventionTips":["Verify transfer completion (size/checksum) before decrypting downloaded files","Use resumable, verified sync rather than raw partial copies"],"tags":["encryption","integrity","truncation"],"backgroundTag":"checksum-mismatch","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}