siyuan-note/siyuan · error

block [%s] is not an instance of attribute view [%s]

Error message

block [%s] is not an instance of attribute view [%s]

What it means

Returned by SetDatabaseBlockVisibleViews (attribute_view.go:1272) when the block referenced by blockID is either not a NodeAttributeView node or its AttributeViewID attribute does not equal the supplied avID. The lookup uses getNodeByBlockID; the type/ID mismatch means the block is not the database block that owns this attribute view.

Source

Thrown at kernel/model/attribute_view.go:1272

		visible[viewID] = true
	}

	var normalized []string
	for _, view := range attrView.Views {
		if visible[view.ID] {
			normalized = append(normalized, view.ID)
		}
	}
	if 1 > len(normalized) {
		return errors.New("at least one visible view is required")
	}

	node, tree, err := getNodeByBlockID(nil, blockID)
	if nil != err {
		return
	}
	if ast.NodeAttributeView != node.Type || node.AttributeViewID != avID {
		return fmt.Errorf("block [%s] is not an instance of attribute view [%s]", blockID, avID)
	}

	err = setNodeAttrs(node, tree, map[string]string{
		av.NodeAttrVisibleViewIDs: strings.Join(normalized, ","),
	})
	return
}

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

func ChangeAttrViewLayout(blockID, avID string, newLayout av.LayoutType) (err error) {
	attrView, err := av.ParseAttributeView(avID)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Send the blockID and avID that actually belong together — read them from the same NodeAttributeView node (node.AttributeViewID paired with the block's ID).
  2. If the block mirrors multiple databases, target the specific mirror's avID, not the canonical one.
  3. Validate node.Type == NodeAttributeView and node.AttributeViewID == avID client-side before submitting.

Example fix

// before: avID taken from the wrong source
transaction({ op: "setAttrViewBlockVisibleViews", blockID, avID: lastOpenedAvID, viewIDs })

// after: read the pair from the node itself
const node = getBlockNode(blockID)
transaction({ op: "setAttrViewBlockVisibleViews", blockID, avID: node.attributeViewID, viewIDs })
Defensive patterns

Strategy: validation

Validate before calling

// Pair blockID with the avID stored on that exact block node.
const node = await fetchBlockAttrs(blockID)
if (node.type !== 'NodeAttributeView' || node.attributeViewID !== avID) {
  throw new Error('block is not an instance of this attribute view')
}

Type guard

function blockOwnsAv(node: BlockAttrs, avID: string): boolean {
  return node.type === 'NodeAttributeView' && node.attributeViewID === avID
}

Prevention

When it happens

Trigger: Calling setAttrViewBlockVisibleViews with a blockID that points to a paragraph/list/heading rather than a database block, or with a blockID whose embedded database (AttributeViewID) differs from operation.AvID — e.g. the block mirrors a different avID, or the IDs were swapped.

Common situations: Frontend sends the avID of one database but the blockID of a block embedding another; copy-paste of a database block where the new block got a new avID but the UI still references the old one; plugin mismatch after mirroring.

Related errors


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