{"record":{"id":"2e8ebcd89a217e60","repo":"siyuan-note/siyuan","slug":"conf-language-0-localized-open-notebook-failure","errorCode":null,"errorMessage":"Conf.Language(0) (localized open notebook failure message)","messagePattern":"Conf\\.Language\\(0\\) \\(localized open notebook failure message\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/assets.go","lineNumber":1313,"sourceCode":"\t\t\tif rootEvalErr != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"resolve assets root [%s] failed: %w\", assetsRoot, rootEvalErr)\n\t\t\t}\n\t\t\tif !gulu.File.IsSubPath(realAssetsRoot, realP) {\n\t\t\t\treturn \"\", fmt.Errorf(\"symlink [%s] resolves outside data/assets: [%s]\", p, realP)\n\t\t\t}\n\t\t\t// 安全校验使用解析后的路径，返回原路径以便下游与 DataDir 保持同一路径形式\n\t\t\treturn p, nil\n\t\t}\n\t\treturn p, nil\n\t}\n\n\t// 在文档同级 assets 文件夹下搜索\n\tif !strings.HasPrefix(relativePath, \"assets/\") {\n\t\treturn \"\", nil\n\t}\n\tnotebooks, err := ListNotebooks()\n\tif err != nil {\n\t\treturn \"\", errors.New(Conf.Language(0))\n\t}\n\tfor _, notebook := range notebooks {\n\t\tif !includeEncrypted && IsEncryptedBox(notebook.ID) {\n\t\t\tcontinue // 加密笔记本的资源不参与全局路径解析（孤岛，资源不跨边界）\n\t\t}\n\t\tnotebookAbsPath := filepath.Join(util.DataDir, notebook.ID)\n\t\tfilelock.Walk(notebookAbsPath, func(path string, d fs.DirEntry, err error) error {\n\t\t\tif isSkipFile(d.Name()) {\n\t\t\t\tif d.IsDir() {\n\t\t\t\t\treturn filepath.SkipDir\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tif p := filepath.ToSlash(path); strings.HasSuffix(p, relativePath) {\n\t\t\t\tif gulu.File.IsExist(path) {\n\t\t\t\t\tabsPath = path\n\t\t\t\t\treturn fs.SkipAll\n\t\t\t\t}","sourceCodeStart":1295,"sourceCodeEnd":1331,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/assets.go#L1295-L1331","documentation":"When resolving an asset that is not under the global assets/ prefix, getAssetAbsPath searches the assets folder of the document's owning notebook; it first calls ListNotebooks to enumerate open notebooks. If that enumeration fails (e.g. the workspace data directory cannot be read), the function aborts with Conf.Language(0), the localized generic \"open notebook failed\" message shown to users.","triggerScenarios":"Calling GetAssetAbsPathWithOpt with a relativePath starting with \"assets/\" while ListNotebooks errors — i.e. the data directory is unreadable, a notebook ID directory is malformed, or workspace state is inconsistent at the moment of the call.","commonSituations":"Corrupted or partially-synced workspace data dir; notebook folders with invalid IDs after a failed sync/restore; permission problems on the data directory; calling the API during startup before notebooks are indexed.","solutions":["Check kernel logs for the underlying ListNotebooks error and fix the unreadable/invalid notebook directory it reports.","Verify the workspace data directory exists and is readable/writable by the kernel process.","Restart the kernel so notebook scanning runs again after the filesystem issue is fixed.","If a specific notebook folder is corrupt, remove or repair it (e.g. restore from sync/backup) so enumeration succeeds."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const resp = await fetch('/api/asset/...');\n  const data = await resp.json();\n} catch (e) {\n  // msg is the localized \"open notebook failed\" text; check kernel logs for the real cause\n  await new Promise(r => setTimeout(r, 1000)); // retry after kernel finishes booting\n}","preventionTips":["Verify the workspace data directory is readable before calling asset APIs","Don't call asset resolution during kernel startup before notebooks are indexed","Watch kernel logs for ListNotebooks errors after failed sync/restore operations","Repair or remove malformed notebook directories promptly"],"tags":["notebooks","filesystem","assets","localized-message"],"backgroundTag":"file-not-found","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}