siyuan-note/siyuan · error
Query notebook failed
Error message
Query notebook failed
What it means
Thrown by getAssetAbsPath (kernel/model/assets.go:1171) when model.ListNotebooks() returns an error during the document-colocated assets search. Conf.Language(0) renders as `Query notebook failed`. It is not about the asset itself but about the kernel's inability to enumerate notebooks (which it needs in order to walk each notebook for an asset whose suffix matches relativePath).
Source
Thrown at kernel/model/assets.go:1171
if rootEvalErr != nil {
return "", fmt.Errorf("resolve assets root [%s] failed: %w", assetsRoot, rootEvalErr)
}
if !gulu.File.IsSubPath(realAssetsRoot, realP) {
return "", fmt.Errorf("symlink [%s] resolves outside data/assets: [%s]", p, realP)
}
// 安全校验使用解析后的路径,返回原路径以便下游与 DataDir 保持同一路径形式
return p, nil
}
return p, nil
}
// 在文档同级 assets 文件夹下搜索
if !strings.HasPrefix(relativePath, "assets/") {
return "", nil
}
notebooks, err := ListNotebooks()
if err != nil {
return "", errors.New(Conf.Language(0))
}
for _, notebook := range notebooks {
if !includeEncrypted && IsEncryptedBox(notebook.ID) {
continue // 加密笔记本的资源不参与全局路径解析(孤岛,资源不跨边界)
}
notebookAbsPath := filepath.Join(util.DataDir, notebook.ID)
filelock.Walk(notebookAbsPath, func(path string, d fs.DirEntry, err error) error {
if isSkipFile(d.Name()) {
if d.IsDir() {
return filepath.SkipDir
}
return nil
}
if p := filepath.ToSlash(path); strings.HasSuffix(p, relativePath) {
if gulu.File.IsExist(path) {
absPath = path
return fs.SkipAll
}View on GitHub (pinned to 251596fc0d)
Solutions
- Check the kernel logs for the underlying ListNotebooks error (it is wrapped/suppressed by Conf.Language(0) here).
- Verify the notebooks directory and each `<boxID>/.siyuan/conf.json` are readable and valid JSON.
- Release any stale filelock (`.siyuan.lock`) and ensure no other kernel process holds the workspace.
- Fix permissions/ownership so the kernel process can read the notebooks directory, then retry.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight notebook enumeration to surface the real underlying error.
if _, err := model.ListNotebooks(); err != nil {
return fmt.Errorf("notebooks unavailable, cannot resolve asset: %w", err)
} Try / catch
if _, err := model.GetAssetAbsPath(ref); err != nil && strings.Contains(err.Error(), "Query notebook failed") {
// ListNotebooks failed; check logs for the wrapped cause (corrupt conf.json / lock / perms)
logging.LogErrorf("notebook enumeration failed during asset resolve")
} Prevention
- Keep notebook conf.json files valid; back up before editing.
- Avoid holding/stalling the workspace filelock from external processes.
- Run the kernel under a user that can read the notebooks directory.
When it happens
Trigger: Calling the global asset resolver for an `assets/...` path that is not found under `data/assets/`, forcing the fallback notebook walk, at a moment when ListNotebooks fails — typically because the notebook configuration/conf.json set cannot be read or parsed, or the underlying filesystem/lock is unavailable.
Common situations: Corrupted or unreadable notebook conf.json after a crash; filelock contention or a locked workspace; permissions preventing the kernel from reading the notebooks directory; a half-written conf.json during sync.
Related errors
- [%s] is not sub path of workspace
- resolve assets directory [%s] failed: %w
- resolve assets root [%s] failed: %w
- directory not found: %s
- not a valid workspace: %s
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/6ad0e193c39742c6.
Report an issue: GitHub.