siyuan-note/siyuan · error

attribute view not found

Error message

attribute view not found: %s

What it means

After passing validation, RemoveUnusedAttributeView looks for the AV's JSON file at data/storage/av/<id>.json. If the file does not exist, the kernel returns this error instead of attempting history archiving/deletion. The database record is already gone, so there is nothing to clean.

Solutions

  1. Confirm the ID is still in the fresh UnusedAttributeViews list before calling; drop stale IDs
  2. Check whether data/storage/av/<id>.json exists; if the record is already gone, treat cleanup as done
  3. Restore the missing AV file from history/backup if you need its data
  4. Re-sync the workspace so the storage/av state is consistent across clients

Example fix

// before: blind removal
await removeUnusedAttributeView(id)
// after: guard on existence
const unused = await getUnusedAttributeViews();
if (unused.some(i => i.Item === id)) await removeUnusedAttributeView(id);
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'fs';
import path from 'path';
const avFile = path.join(dataDir, 'storage', 'av', id + '.json');
if (!fs.existsSync(avFile)) { /* already removed; skip */ }

Try / catch

try { await removeUnusedAttributeView(id) } catch (e) {
  if (e.message.includes('attribute view not found')) {
    // treat as already-cleaned; drop id from worklist
    return;
  }
}

Prevention

When it happens

Trigger: Calling RemoveUnusedAttributeView for an ID whose storage/av/<id>.json file is missing — the AV file was deleted externally, the ID was already removed by another client, or the storage folder was cleaned/restored from a partial backup.

Common situations: Manual deletion of files under data/storage/av; sync conflicts removing the JSON; repeated API calls after a successful removal (retry with stale ID); restoring a workspace backup that lacks the AV file.

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@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/049dfb7e472c2467. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/attribute_view.go:76

	}
	for _, item := range UnusedAttributeViews(false) {
		if item.Item == id {
			return nil
		}
	}
	return fmt.Errorf("attribute view is not unused: %s", id)
}

func RemoveUnusedAttributeView(id string) (err error) {
	// 防御性校验:ID 必须是合法的节点 ID 格式,防止通过路径穿越读取或删除任意文件
	if err = ValidateUnusedAttributeView(id); err != nil {
		return
	}

	base := filepath.Join(util.DataDir, "storage", "av")
	absPath := filepath.Join(base, id+".json")
	if !filelock.IsExist(absPath) {
		return fmt.Errorf("attribute view not found: %s", id)
	}

	historyDir, err := getHistoryDir(HistoryOpClean)
	if err != nil {
		logging.LogErrorf("get history dir failed: %s", err)
		return
	}

	newP := strings.TrimPrefix(absPath, util.DataDir)
	historyPath := filepath.Join(historyDir, newP)
	if filelock.IsExist(absPath) {
		if err = filelock.Copy(absPath, historyPath); err != nil {
			return
		}
	}

	if err = filelock.RemoveWithoutFatal(absPath); err != nil {
		logging.LogErrorf("remove unused asset [%s] failed: %s", absPath, err)

View on GitHub (pinned to 9f775e8a12)