siyuan-note/siyuan · error

Conf.Language(0) (localized open notebook failure message)

Error message

Conf.Language(0) (localized open notebook failure message)

What it means

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.

Source

Thrown at kernel/model/assets.go:1313

			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 8641553a1f)

Solutions

  1. Check kernel logs for the underlying ListNotebooks error and fix the unreadable/invalid notebook directory it reports.
  2. Verify the workspace data directory exists and is readable/writable by the kernel process.
  3. Restart the kernel so notebook scanning runs again after the filesystem issue is fixed.
  4. If a specific notebook folder is corrupt, remove or repair it (e.g. restore from sync/backup) so enumeration succeeds.
Defensive patterns

Strategy: retry

Try / catch

try {
  const resp = await fetch('/api/asset/...');
  const data = await resp.json();
} catch (e) {
  // msg is the localized "open notebook failed" text; check kernel logs for the real cause
  await new Promise(r => setTimeout(r, 1000)); // retry after kernel finishes booting
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/2e8ebcd89a217e60. Report an issue: GitHub.