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

  1. Check the kernel logs for the underlying ListNotebooks error (it is wrapped/suppressed by Conf.Language(0) here).
  2. Verify the notebooks directory and each `<boxID>/.siyuan/conf.json` are readable and valid JSON.
  3. Release any stale filelock (`.siyuan.lock`) and ensure no other kernel process holds the workspace.
  4. 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

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


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/6ad0e193c39742c6. Report an issue: GitHub.