siyuan-note/siyuan · error

at least one visible view is required

Error message

at least one visible view is required

What it means

SetDatabaseBlockVisibleViews requires at least one view ID in the viewIDs list; an empty list is rejected before the attribute view is even parsed. A database block must always keep at least one visible view so the block remains renderable.

Solutions

  1. Always include at least one existing view ID in viewIDs; if hiding the last view, reset to all view IDs or keep a default view visible.
  2. On the caller side, check viewIDs.length >= 1 before invoking the API.
  3. If the intent is to delete a view rather than hide it, use the view-delete operation instead of visible-view setting.

Example fix

// before
setVisibleViews(avID, []);
// after
const ids = computeVisibleViews();
setVisibleViews(avID, ids.length ? ids : [getDefaultViewId(avID)]);
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(viewIDs) || viewIDs.length < 1) throw new Error('at least one visible view id required');

Type guard

const isNonEmptyStringArray = (v: unknown): v is string[] => Array.isArray(v) && v.length > 0 && v.every(x => typeof x === 'string');

Try / catch

try { await setVisibleViews(blockID, avID, viewIDs); } catch (e) { if (String(e).includes('at least one visible view')) { await setVisibleViews(blockID, avID, allViewIds); } else throw e; }

Prevention

When it happens

Trigger: Calling SetDatabaseBlockVisibleViews (kernel API, via doSetAttrViewBlockVisibleViews) with viewIDs = [] or nil.

Common situations: Frontend hides views one by one and accidentally hides the last one; plugin computes visible view IDs from a filter that matched nothing; serialization bug dropping empty arrays.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/dd34bac9a59850d4. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/attribute_view.go:1386

func (tx *Transaction) doSetAttrViewBlockView(operation *Operation) (ret *TxErr) {
	err := SetDatabaseBlockView(operation.BlockID, operation.AvID, operation.ID)
	if err != nil {
		return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}
	}
	return
}

func (tx *Transaction) doSetAttrViewBlockVisibleViews(operation *Operation) (ret *TxErr) {
	err := SetDatabaseBlockVisibleViews(operation.BlockID, operation.AvID, operation.ViewIDs)
	if err != nil {
		return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}
	}
	return
}

func SetDatabaseBlockVisibleViews(blockID, avID string, viewIDs []string) (err error) {
	if 1 > len(viewIDs) {
		return errors.New("at least one visible view is required")
	}

	attrView, err := av.ParseAttributeView(avID)
	if nil != err {
		logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
		return
	}

	visible := map[string]bool{}
	for _, viewID := range viewIDs {
		if nil == attrView.GetView(viewID) {
			return fmt.Errorf("view [%s] not found in attribute view [%s]", viewID, avID)
		}
		visible[viewID] = true
	}

	var normalized []string
	for _, view := range attrView.Views {

View on GitHub (pinned to 9f775e8a12)