{"record":{"id":"5da3439748b66085","repo":"siyuan-note/siyuan","slug":"view-not-found","errorCode":null,"errorMessage":"view not found","messagePattern":"view not found","errorType":"http","errorClass":"ErrViewNotFound","httpStatus":null,"severity":"error","filePath":"kernel/av/av.go","lineNumber":1296,"sourceCode":"\tret = filepath.Join(av, avID+\".json\")\n\tif !gulu.File.IsDir(av) {\n\t\tif err := os.MkdirAll(av, 0755); err != nil {\n\t\t\tlogging.LogErrorf(\"create attribute view dir failed: %s\", err)\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\nfunc GetAttributeViewI18n(key string) string {\n\treturn util.AttrViewLangs[util.Lang][key].(string)\n}\n\nvar (\n\tErrAttributeViewNotFound  = errors.New(\"attribute view not found\")\n\tErrInvalidAttributeViewID = errors.New(\"invalid attribute view id\")\n\tErrInvalidBoxID           = errors.New(\"invalid box id\")\n\tErrViewNotFound           = errors.New(\"view not found\")\n\tErrKeyNotFound            = errors.New(\"key not found\")\n\tErrItemNotFound           = errors.New(\"item not found\")\n\tErrWrongLayoutType        = errors.New(\"wrong layout type\")\n\tErrInvalidColumnAlign     = errors.New(\"invalid column align\")\n\tErrSpecTooNew             = errors.New(\"attribute view spec is too new\")\n\tErrFilterTooDeep          = errors.New(\"filter nesting depth exceeds the maximum allowed\")\n)\n\nconst (\n\tNodeAttrNameAvs        = \"custom-avs\"                 // 用于标记块所属的属性视图，逗号分隔 av id\n\tNodeAttrView           = \"custom-sy-av-view\"          // 用于标记块所属的属性视图视图 view id Database block support specified view https://github.com/siyuan-note/siyuan/issues/10443\n\tNodeAttrVisibleViewIDs = \"custom-sy-av-visible-views\" // 用于标记数据库块显示的视图 ID，逗号分隔\n\tNodeAttrViewStaticText = \"custom-sy-av-s-text\"        // 用于标记块所属的属性视图静态文本 Database-bound block primary key supports setting static anchor text https://github.com/siyuan-note/siyuan/issues/10049\n\n\tNodeAttrViewNames = \"av-names\" // 用于临时标记块所属的属性视图名称，空格分隔\n)\n","sourceCodeStart":1278,"sourceCodeEnd":1313,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/av/av.go#L1278-L1313","documentation":"ErrViewNotFound is a sentinel error in the SiYuan attribute-view (database) engine. It means no view with the given view ID exists inside the AttributeView, or the attribute-view JSON file itself could not be found on disk (parseAttributeViewByPathInBox at kernel/av/av.go:785 maps a missing file to this same error). Views are per-AttributeView objects stored in av.Views; GetFirstView (kernel/av/av.go:1061) also returns it when the Views array holds no usable view.","triggerScenarios":"Calling model.RenderAttributeViewWithTarget or any transaction operation with a viewID that is not in attrView.Views; a database block whose custom-sy-av-view attribute points to a deleted view; GetFirstView on an AttributeView with an empty Views slice; ParseAttributeView on an avID whose storage/{avID}.json file no longer exists (parseAttributeViewByPathInBox sets err = ErrViewNotFound when filelock.IsExist fails). The API layer (kernel/api/av.go:1370) detects it and returns ret.Data = {\"error\": \"viewNotFound\"}.","commonSituations":"A view tab was deleted in another tab/window while a stale render request arrives; sync or data rollback removed the .av.json; frontend holds a cached viewID after the database was rebuilt; code copies a viewID from one AttributeView to another (IDs are only unique per AttributeView).","solutions":["Fetch fresh view IDs first: parse the AttributeView (av.ParseAttributeView) and pick the ID from attrView.Views or GetVisibleViewIDs instead of reusing a cached viewID","If the database block is stale, clear or update its custom-sy-av-view attribute so it falls back to the first view","Check that the attribute-view file exists before parsing if the avID may have been deleted (filelock.IsExist on the resolved path)","In API handlers, branch on errors.Is(err, av.ErrViewNotFound) and return the viewNotFound marker so the frontend can re-request views"],"exampleFix":"// before: viewID cached from an earlier response\nview, av2, _, err := model.RenderAttributeViewWithTarget(blockID, avID, cachedViewID, ...)\nif err != nil { return err }\n\n// after: validate the view ID against the current attribute view\nattrView, err := av.ParseAttributeView(avID)\nif err != nil { return err }\nif nil == attrView.GetView(cachedViewID) {\n    cachedViewID = \"\" // let the renderer pick the first visible view\n}\nview, av2, _, err := model.RenderAttributeViewWithTarget(blockID, avID, cachedViewID, ...)\nif errors.Is(err, av.ErrViewNotFound) {\n    // re-read views and retry once with the first view\n}","handlingStrategy":"validation","validationCode":"attrView, err := av.ParseAttributeView(avID)\nif err != nil {\n    return err // includes ErrViewNotFound when the .av.json is missing\n}\nview := attrView.GetView(viewID)\nif nil == view {\n    ids := attrView.GetVisibleViewIDs(\"\")\n    if 0 == len(ids) {\n        return av.ErrViewNotFound // no views at all\n    }\n    viewID = ids[0]\n}","typeGuard":"func isViewNotFound(err error) bool {\n    return errors.Is(err, av.ErrViewNotFound)\n}","tryCatchPattern":"if err != nil {\n    if errors.Is(err, av.ErrViewNotFound) {\n        // refresh views, fall back to first visible view, or show 'view deleted' UI\n    }\n}","preventionTips":["Never cache viewIDs across renders; take them from the latest getAttributeView response","When deleting a view, update dependent database-block attributes (custom-sy-av-view) in the same transaction","Treat an empty view list as data corruption: re-create a default table view instead of retrying"],"tags":["siyuan","attribute-view","database","not-found","go"],"backgroundTag":"view-id-not-found","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}