{"record":{"id":"d045419d51f03c89","repo":"siyuan-note/siyuan","slug":"conf-language-0-assets","errorCode":null,"errorMessage":"Conf.Language(0)","messagePattern":"Conf\\.Language\\(0\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/assets.go","lineNumber":1317,"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":1299,"sourceCodeEnd":1335,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/assets.go#L1299-L1335","documentation":"In getAssetAbsPath, the doc-level assets search begins with ListNotebooks(); if listing notebooks fails, the function aborts with Conf.Language(0) (\"Query notebook failed\"). The error means the notebook inventory itself could not be read, not that the asset is missing.","triggerScenarios":"getAssetAbsPath (via GetAssetAbsPathWithOpt) reaches the per-notebook search for a relativePath starting with 'assets/' and ListNotebooks() returns an error — e.g. the data directory is unreadable, a notebook config (.siyuan/conf.json) is corrupt, or an I/O error occurs while scanning notebooks.","commonSituations":"Corrupted workspace data directory; file-permission problems after restoring a workspace as another user; a broken notebook folder that breaks notebook enumeration; disk I/O errors on external drives.","solutions":["Check kernel logs for the underlying ListNotebooks failure and fix the reported notebook/data issue","Verify read permissions on <workspace>/data and each notebook directory","Restart the kernel so notebooks are re-scanned; remove or repair broken notebook folders","If the workspace was restored from backup, ensure notebook .siyuan config files are intact"],"exampleFix":"// before\nabs, err := model.GetAssetAbsPathWithOpt(rel, false)\n// after (diagnose root cause)\nif _, nbErr := model.ListNotebooks(); nbErr != nil {\n    return fmt.Errorf(\"notebook listing broken, fix workspace first: %w\", nbErr)\n}\nabs, err := model.GetAssetAbsPathWithOpt(rel, false)","handlingStrategy":"retry","validationCode":"if _, err := model.ListNotebooks(); err != nil {\n    return fmt.Errorf(\"fix notebook listing before resolving assets: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"abs, err := model.GetAssetAbsPath(rel)\nif err != nil && strings.Contains(err.Error(), \"Query notebook failed\") {\n    // check kernel logs for the underlying notebook scan error\n    return restartKernelAndRetry()\n}","preventionTips":["Keep notebook .siyuan config files intact","Ensure the process has read access to the whole data directory","Restart the kernel after restoring or moving workspaces"],"tags":["go","notebooks","filesystem","assets"],"backgroundTag":"database-query-failed","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"}