{"record":{"id":"be6cc0978e6d2084","repo":"siyuan-note/siyuan","slug":"errinvalidid","errorCode":"ErrInvalidID","errorMessage":"invalid id","messagePattern":"invalid id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/tree.go","lineNumber":216,"sourceCode":"\tif err = treenode.CheckSpecJSON(data); nil != err {\n\t\treturn\n\t}\n\tret, err = dataparser.ParseJSONWithoutFix(data, luteEngine.ParseOptions)\n\tif err != nil {\n\t\tlogging.LogErrorf(\"parse json to tree [%s] failed: %s\", localPath, err)\n\t\treturn\n\t}\n\treturn\n}\n\nvar (\n\tErrBoxNotFound   = errors.New(\"notebook not found\")\n\tErrBoxClosed     = errors.New(\"notebook closed\")\n\tErrBlockNotFound = errors.New(\"block not found\")\n\tErrTreeNotFound  = errors.New(\"tree not found\")\n\tErrIndexing      = errors.New(\"indexing\")\n\tErrBoxUnindexed  = errors.New(\"notebook unindexed\")\n\tErrInvalidID     = errors.New(\"invalid id\")\n)\n\nfunc LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) {\n\treturn LoadTreeByBlockIDWithReindexInBox(id, \"\")\n}\n\n// LoadTreeByBlockIDWithReindexInBox 与 LoadTreeByBlockIDWithReindex 一致，但按 boxID 路由 blocktree 查询。\nfunc LoadTreeByBlockIDWithReindexInBox(id, boxID string) (ret *parse.Tree, err error) {\n\tif \"\" == id {\n\t\tlogging.LogWarnf(\"block id is empty\")\n\t\treturn nil, ErrTreeNotFound\n\t}\n\n\tbt := treenode.GetBlockTreeInBox(id, boxID)\n\tif nil == bt && \"\" == boxID {\n\t\t// boxID 未知时（如通用打开入口），遍历所有已打开的加密笔记本查找\n\t\tfor _, encBoxID := range treenode.GetOpenedEncryptedBoxIDs() {\n\t\t\tif encBT := treenode.GetBlockTreeInBox(id, encBoxID); nil != encBT {","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/tree.go#L198-L234","documentation":"ErrInvalidID is the sentinel error for an ID that does not match the required node-ID pattern (ast.IsNodeIDPattern: timestamp-random alphanumeric form). Attribute-view rendering and repo-snapshot AV resolution return it before doing any I/O when the supplied avID is structurally invalid.","triggerScenarios":"RenderAttributeViewWithTarget called with an avID that is not a valid node ID (e.g. an empty string, a view name, or a user-typed identifier); ResolveRepoSnapshotAttributeViewBoxID invoked with a malformed avID from snapshot metadata.","commonSituations":"Plugins passing an attribute-view *name* or database config key instead of the av ID; hand-edited templates or snapshots with corrupted IDs; truncated IDs from logs or user copy-paste.","solutions":["Validate the avID with ast.IsNodeIDPattern (or the same regex) before calling; ensure it is the av block's node ID, not its name","Fetch the correct av ID from the document tree (the attribute-view node's ID) or via SQL from the blocks table","Correct corrupted snapshot/template metadata if the stored avID itself is malformed"],"exampleFix":"// before\nRenderAttributeView(avID, viewID, ...)\n// after\nif !ast.IsNodeIDPattern(avID) {\n    return fmt.Errorf(\"invalid av id: %q\", avID)\n}\nRenderAttributeView(avID, viewID, ...)","handlingStrategy":"validation","validationCode":"if !ast.IsNodeIDPattern(avID) {\n    return fmt.Errorf(\"invalid av id: %q\", avID)\n}","typeGuard":"func isValidNodeID(id string) bool { return ast.IsNodeIDPattern(id) }","tryCatchPattern":"if errors.Is(err, model.ErrInvalidID) {\n    return fmt.Errorf(\"check the av ID: %w\", err)\n}","preventionTips":["Pass the attribute-view node's ID, never its display name","Copy IDs programmatically rather than by hand from logs","Validate IDs with ast.IsNodeIDPattern before any model call"],"tags":["go","id","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}