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
- 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.
- On the caller side, check viewIDs.length >= 1 before invoking the API.
- 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
- Never compute visibility from an empty filter result without a fallback
- Keep a default view always visible when hiding views
- Treat 'hide last view' UI action as 'reset to all views'
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
- attribute view custom color index
- attribute view custom color must not be null
- attribute view custom colors count exceeds the
- attribute view custom colors must not be empty
- attribute view is not unused
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)