siyuan-note/siyuan · error · ErrViewNotFound

view not found

Error message

view not found

What it means

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.

Solutions

  1. 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
  2. If the database block is stale, clear or update its custom-sy-av-view attribute so it falls back to the first view
  3. Check that the attribute-view file exists before parsing if the avID may have been deleted (filelock.IsExist on the resolved path)
  4. In API handlers, branch on errors.Is(err, av.ErrViewNotFound) and return the viewNotFound marker so the frontend can re-request views

Example fix

// before: viewID cached from an earlier response
view, av2, _, err := model.RenderAttributeViewWithTarget(blockID, avID, cachedViewID, ...)
if err != nil { return err }

// after: validate the view ID against the current attribute view
attrView, err := av.ParseAttributeView(avID)
if err != nil { return err }
if nil == attrView.GetView(cachedViewID) {
    cachedViewID = "" // let the renderer pick the first visible view
}
view, av2, _, err := model.RenderAttributeViewWithTarget(blockID, avID, cachedViewID, ...)
if errors.Is(err, av.ErrViewNotFound) {
    // re-read views and retry once with the first view
}
Defensive patterns

Strategy: validation

Validate before calling

attrView, err := av.ParseAttributeView(avID)
if err != nil {
    return err // includes ErrViewNotFound when the .av.json is missing
}
view := attrView.GetView(viewID)
if nil == view {
    ids := attrView.GetVisibleViewIDs("")
    if 0 == len(ids) {
        return av.ErrViewNotFound // no views at all
    }
    viewID = ids[0]
}

Type guard

func isViewNotFound(err error) bool {
    return errors.Is(err, av.ErrViewNotFound)
}

Try / catch

if err != nil {
    if errors.Is(err, av.ErrViewNotFound) {
        // refresh views, fall back to first visible view, or show 'view deleted' UI
    }
}

Prevention

When it happens

Trigger: 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"}.

Common situations: 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).

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/5da3439748b66085. Report an issue: GitHub.

Appendix: source

Thrown at kernel/av/av.go:1296

	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)