siyuan-note/siyuan · error
invalid attribute view ID
Error message
invalid attribute view ID: %s
What it means
ValidateUnusedAttributeView first checks that the supplied ID matches the node-ID pattern (ast.IsNodeIDPattern). A non-conforming ID fails immediately with this error. This is a defensive check so downstream file operations (which build paths from the ID) cannot be abused for path traversal or target arbitrary files.
Solutions
- Pass the exact attribute-view ID as listed by UnusedAttributeViews output (item.Item)
- Validate the ID client-side against the node-ID pattern before calling
- Do not accept free-text IDs from users in plugins/scripts; select from the unused-AV list instead
Example fix
// before
fetchPost('/api/attr/removeUnusedAttributeView', { id: userInput })
// after
if (!/^[0-9a-f]{20,}$/.test(id)) throw new Error('bad AV id');
fetchPost('/api/attr/removeUnusedAttributeView', { id }) Defensive patterns
Strategy: validation
Validate before calling
// SiYuan node IDs are time-ordered hex strings
function looksLikeNodeID(id) {
return typeof id === 'string' && /^[0-9a-f]{14,26}$/.test(id);
}
if (!looksLikeNodeID(id)) throw new Error('invalid AV id'); Type guard
const isNodeID = (v) => typeof v === 'string' && v.length > 0 && !v.includes('/') && !v.includes('..') && /^[0-9a-f]+$/.test(v); Try / catch
try { await removeUnusedAttributeView(id) } catch (e) {
if (e.message.includes('invalid attribute view ID')) {
// caller supplied a malformed id; surface to user/plugin developer
}
} Prevention
- Always source AV IDs from UnusedAttributeViews output, not free text
- Reject IDs containing path characters at the plugin boundary
- Keep IDs intact through URL encoding/decoding
When it happens
Trigger: Calling the RemoveUnusedAttributeView API (or ValidateUnusedAttributeView directly) with an id that is not a 64-bit-hex-style node ID — e.g. containing '/', '..\\', empty string, or random text.
Common situations: Hand-crafted API calls with guessed or user-supplied IDs; plugins passing a database/AV key instead of a block/AV ID; URL-encoding or truncation mangling the ID; hostile requests probing for path traversal.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- ErrInvalidAttributeViewID
- ErrInvalidBoxID
- invalid new item template id
- at least one visible view is required
- attribute view custom color index
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/ea3760c3873b634e.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/attribute_view.go:57
"github.com/88250/lute/ast"
"github.com/88250/lute/parse"
"github.com/gin-gonic/gin"
"github.com/jinzhu/copier"
"github.com/siyuan-note/filelock"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/av"
"github.com/siyuan-note/siyuan/kernel/cache"
"github.com/siyuan-note/siyuan/kernel/filesys"
"github.com/siyuan-note/siyuan/kernel/search"
"github.com/siyuan-note/siyuan/kernel/sql"
"github.com/siyuan-note/siyuan/kernel/treenode"
"github.com/siyuan-note/siyuan/kernel/util"
"github.com/xrash/smetrics"
)
func ValidateUnusedAttributeView(id string) error {
if !ast.IsNodeIDPattern(id) {
return fmt.Errorf("invalid attribute view ID: %s", id)
}
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) {View on GitHub (pinned to 9f775e8a12)