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
- Confirm the ID is still in the fresh UnusedAttributeViews list before calling; drop stale IDs
- Check whether data/storage/av/<id>.json exists; if the record is already gone, treat cleanup as done
- Restore the missing AV file from history/backup if you need its data
- 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
- Never manually delete files under data/storage/av while the app runs
- Make removal calls idempotent: ignore not-found on retries
- Restore missing AV files from history/backup before cleanup
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
- [/api/av/batchSetAttributeViewBlockAttrs] parameter [rowID]…
- at least one visible view is required
- attribute view content is unavailable
- attribute view custom color
- attribute view custom color
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)