{"record":{"id":"8a6ae83e183dbd5a","repo":"siyuan-note/siyuan","slug":"failed-to-insert-asset-file-please-reopen-the-doc","errorCode":null,"errorMessage":"Failed to insert asset file, please reopen the document","messagePattern":"Failed to insert asset file, please reopen the document","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/upload.go","lineNumber":43,"sourceCode":"\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/88250/gulu\"\n\t\"github.com/88250/lute/ast\"\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/siyuan-note/filelock\"\n\t\"github.com/siyuan-note/logging\"\n\t\"github.com/siyuan-note/siyuan/kernel/cache\"\n\t\"github.com/siyuan-note/siyuan/kernel/treenode\"\n\t\"github.com/siyuan-note/siyuan/kernel/util\"\n)\n\n// InsertAssetBytes 将内存中的资源直接写入目标文档资源目录，避免生成内容经过明文临时文件。\nfunc InsertAssetBytes(id, fileName string, data []byte) (assetPath string, created bool, err error) {\n\tbt := treenode.GetBlockTree(id)\n\tif bt == nil {\n\t\treturn \"\", false, errors.New(Conf.Language(71))\n\t}\n\tif len(data) == 0 {\n\t\treturn \"\", false, errors.New(\"asset data is empty\")\n\t}\n\n\tbaseName := filepath.Base(fileName)\n\tfName := util.FilterUploadFileName(baseName)\n\text := strings.ToLower(filepath.Ext(fName))\n\tfName = strings.TrimSuffix(fName, filepath.Ext(fName)) + ext\n\tif fName == \"\" || fName == \".\" || ext == \"\" {\n\t\treturn \"\", false, errors.New(\"invalid asset filename\")\n\t}\n\n\tdocDirLocalPath := filepath.Join(util.DataDir, bt.BoxID, path.Dir(bt.Path))\n\tassetsDirPath := getAssetsDir(filepath.Join(util.DataDir, bt.BoxID), docDirLocalPath)\n\tif err = os.MkdirAll(assetsDirPath, 0755); err != nil {\n\t\treturn \"\", false, err\n\t}","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/upload.go#L25-L61","documentation":"Thrown by InsertAssetBytes when treenode.GetBlockTree(id) returns nil, meaning the provided block ID does not exist in the in-memory block tree (blocktree.db). Conf.Language(71) resolves to the localized message 'Failed to insert asset file, please reopen the document'. The function is designed to write asset bytes directly into a document's assets directory, and it needs the block's BoxID and Path to locate that directory, so a missing block tree entry is fatal.","triggerScenarios":"Calling InsertAssetBytes with a block ID that was never indexed, was deleted, or belongs to a notebook whose block tree hasn't been loaded yet. Also triggered right after a kernel restart if the block tree is still rebuilding from disk.","commonSituations":"The document was just created and its .sy file hasn't been indexed into blocktree.db yet; the block was removed in a concurrent transaction; the workspace was just opened and indexing is incomplete; a stale block ID was cached client-side after a sync conflict.","solutions":["Ensure the document is fully loaded and indexed before inserting assets — call the kernel API to open/index the document first","Verify the block ID still exists via the block tree query API before calling InsertAssetBytes","Reopen the document in the UI to force a re-index, then retry the insert","If this happens after kernel startup, wait for the boot indexing phase to complete (check server status endpoint)"],"exampleFix":"// before\nassetPath, created, err := model.InsertAssetBytes(blockID, \"file.png\", data)\n\n// after\nif bt := treenode.GetBlockTree(blockID); bt == nil {\n    // trigger re-index or report stale block\n    return fmt.Errorf(\"block %s not found, reopen the document\", blockID)\n}\nassetPath, created, err := model.InsertAssetBytes(blockID, \"file.png\", data)","handlingStrategy":"validation","validationCode":"// Go caller — check block tree before inserting\nbt := treenode.GetBlockTree(blockID)\nif bt == nil {\n    // trigger re-index or return a clear error to the user\n    return fmt.Errorf(\"block %s not in tree; reopen the document\", blockID)\n}\nassetPath, created, err := model.InsertAssetBytes(blockID, fileName, data)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always verify a block ID exists in the block tree before any asset operation that depends on it","After kernel startup, wait for the indexing phase to complete before processing asset inserts","Handle the case where a user closes or deletes a document mid-operation by re-validating block IDs"],"tags":["asset","blocktree","upload","kernel"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}