siyuan-note/siyuan · error

view [%s] not found

Error message

view [%s] not found

What it means

Thrown by setAttributeViewFieldsHidden when one of the viewIDs in the operation does not resolve to a view in the AttributeView (attrView.GetView(viewID) returns nil). Hidden-state changes are applied per view, so every referenced view must exist.

Source

Thrown at kernel/model/attribute_view.go:6505

	if err != nil {
		return
	}
	err = av.SaveAttributeView(attrView)
	return
}

func setAttributeViewFieldsHidden(attrView *av.AttributeView, keyID string, viewIDs []string, hidden bool) (err error) {
	var fields []*av.BaseField
	seen := map[string]bool{}
	for _, viewID := range viewIDs {
		if seen[viewID] {
			continue
		}
		seen[viewID] = true

		view := attrView.GetView(viewID)
		if nil == view {
			return fmt.Errorf("view [%s] not found", viewID)
		}
		field := getAttributeViewField(view, keyID)
		if nil == field {
			return fmt.Errorf("field [%s] not found in view [%s]", keyID, viewID)
		}
		fields = append(fields, field)
	}

	if 1 > len(fields) {
		return errors.New("view IDs is empty")
	}
	for _, field := range fields {
		field.Hidden = hidden
	}
	return
}

func getAttributeViewField(view *av.View, keyID string) (ret *av.BaseField) {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Filter the viewIDs list against the AV's current views before sending the hide/show operation.
  2. Refresh view metadata on the client when views are added/removed and invalidate cached viewIDs.
  3. Drop unknown viewIDs silently on the client rather than failing the whole batch.

Example fix

// before
setAttributeViewFieldsHidden(attrView, keyID, [viewID1, deletedViewID], true)
// after
liveViewIDs := filterExisting(attrView.Views, operation.ViewIDs)
setAttributeViewFieldsHidden(attrView, keyID, liveViewIDs, true)
Defensive patterns

Strategy: validation

Validate before calling

const liveViewIDs = new Set(attrView.views.map(v => v.id))
const safeIDs = operation.viewIDs.filter(id => liveViewIDs.has(id))
if (safeIDs.length === 0) { /* nothing to do; skip the op */ }

Try / catch

try { await performTx([hideOp]) } catch (e) {
  if (/view \[.*\] not found/.test(String(e.message ?? e))) { reloadViews(avID) } else { throw e }
}

Prevention

When it happens

Trigger: Passing a viewID that was deleted, belongs to another AV, or is malformed; an undo replay referencing a view that a later operation removed; multi-select hidden toggle where one of the selected views no longer exists.

Common situations: Stale viewID cached on the client after the user deleted a view; concurrent view deletion during a bulk hide/show operation.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/a86e482cc686b313. Report an issue: GitHub.