siyuan-note/siyuan · error · ErrInvalidAttributeViewID
invalid attribute view id
Error message
invalid attribute view id
What it means
Sentinel error av.ErrInvalidAttributeViewID (kernel/av/av.go:1294). ParseAttributeView (av.go:739), ParseAttributeViewInBox (av.go:758), SaveAttributeView (av.go:892) and the encrypted-box hook (encrypted_hook.go:206) reject any avID that fails lute's ast.IsNodeIDPattern — the fixed-format node-ID pattern used for all SiYuan block/av IDs. Because the ID becomes a filename under storage/av/, this doubles as a path-traversal guard: '../outside', 'nested/outside' and similar are rejected (covered by kernel/av/path_test.go).
Solutions
- Use IDs produced by the system: av.NewAttributeView() / ast.NewNodeID(), or an avID copied from an existing database block's custom-avs attribute
- Validate the ID shape before calling (fixed-length node-ID pattern, no slashes/dots)
- Fetch the correct ID via the av APIs rather than guessing
- If you maintain external tooling, keep the avID mapping table so IDs are never reconstructed from names
Example fix
// before
avView, err := av.ParseAttributeView("my-database")
// after
avID := ast.NewNodeID() // or an id obtained from an existing av
avView, err := av.ParseAttributeView(avID) Defensive patterns
Strategy: type-guard
Validate before calling
// Go callers: validate before calling any av API
if !ast.IsNodeIDPattern(avID) {
return fmt.Errorf("rejecting malformed attribute view id %q", avID)
}
_, err := av.ParseAttributeView(avID) Type guard
func isValidAvID(id string) bool {
return ast.IsNodeIDPattern(id) // same pattern the kernel enforces; rejects paths and names
} Try / catch
if _, err := av.ParseAttributeView(avID); err != nil {
if errors.Is(err, av.ErrInvalidAttributeViewID) {
// the id is malformed or contains path characters: do not retry, reject the input
}
} Prevention
- Only use IDs minted by av.NewAttributeView() or ast.NewNodeID() — never user-typed names
- Treat avIDs as opaque tokens: store and forward them verbatim
- Validate ids at the trust boundary in plugins before passing them to kernel APIs
- Never build avIDs from path fragments — the check is also a path-traversal guard
When it happens
Trigger: Passing a human-chosen name ('mydb'), a file path ('../outside'), an empty string, or any non-pattern string as avID to an /api/av/* endpoint or to the kernel Go functions; plugins feeding user input straight into ParseAttributeView.
Common situations: Plugin authors inventing their own ID scheme instead of using av.NewAttributeView(); API scripts copying an av 'name' where the ID belongs; IDs mangled by URL truncation or encoding.
Related errors
- attribute view not found
- cannot remove primary key field
- clone attribute view value
- current document is not bound to the context filter target…
- database back relation changed since document deletion
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/efe0da854916af88.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/av/av.go:1294
av := filepath.Join(util.DataDir, "storage", "av")
ret = filepath.Join(av, avID+".json")
if !gulu.File.IsDir(av) {
if err := os.MkdirAll(av, 0755); err != nil {
logging.LogErrorf("create attribute view dir failed: %s", err)
return
}
}
return
}
func GetAttributeViewI18n(key string) string {
return util.AttrViewLangs[util.Lang][key].(string)
}
var (
ErrAttributeViewNotFound = errors.New("attribute view not found")
ErrInvalidAttributeViewID = errors.New("invalid attribute view id")
ErrInvalidBoxID = errors.New("invalid box id")
ErrViewNotFound = errors.New("view not found")
ErrKeyNotFound = errors.New("key not found")
ErrItemNotFound = errors.New("item not found")
ErrWrongLayoutType = errors.New("wrong layout type")
ErrInvalidColumnAlign = errors.New("invalid column align")
ErrSpecTooNew = errors.New("attribute view spec is too new")
ErrFilterTooDeep = errors.New("filter nesting depth exceeds the maximum allowed")
)
const (
NodeAttrNameAvs = "custom-avs" // 用于标记块所属的属性视图,逗号分隔 av id
NodeAttrView = "custom-sy-av-view" // 用于标记块所属的属性视图视图 view id Database block support specified view https://github.com/siyuan-note/siyuan/issues/10443
NodeAttrVisibleViewIDs = "custom-sy-av-visible-views" // 用于标记数据库块显示的视图 ID,逗号分隔
NodeAttrViewStaticText = "custom-sy-av-s-text" // 用于标记块所属的属性视图静态文本 Database-bound block primary key supports setting static anchor text https://github.com/siyuan-note/siyuan/issues/10049
NodeAttrViewNames = "av-names" // 用于临时标记块所属的属性视图名称,空格分隔
)View on GitHub (pinned to afa823b6b4)