siyuan-note/siyuan · error

previous attribute view [%s] is not bound

Error message

previous attribute view [%s] is not bound

What it means

When inserting an attribute view at a position after a reference view, the kernel searches the bound-view list for previousAvID; if it is not found the insertion point is undefined and this error is returned.

Source

Thrown at kernel/model/attribute_view.go:8632

			index = i
			break
		}
	}
	if 0 > index {
		return nil, fmt.Errorf("attribute view [%s] is not bound", avID)
	}

	ret = append(ret[:index], ret[index+1:]...)
	previousIndex := -1
	if "" != previousAvID {
		for i, id := range ret {
			if id == previousAvID {
				previousIndex = i
				break
			}
		}
		if 0 > previousIndex {
			return nil, fmt.Errorf("previous attribute view [%s] is not bound", previousAvID)
		}
	}

	ret = util.InsertElem(ret, previousIndex+1, avID)
	return
}

func bindBlockAv(tx *Transaction, avID, blockID string) {
	node, tree, err := getNodeByBlockID(tx, blockID)
	if err != nil {
		return
	}

	bindBlockAv0(tx, avID, node, tree)
	return
}

func bindBlockAv0(tx *Transaction, avID string, node *ast.Node, tree *parse.Tree) {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Pass an empty previousAvID to append, or a previousAvID currently present in the bound list
  2. Refresh the block's bound view list before computing previousAvID
  3. Validate previousAvID membership before the call

Example fix

// before
bindAttrView(blockID, avID, stalePreviousAvID)
// after
const ids = getBoundAvIDs(blockID); bindAttrView(blockID, avID, ids.includes(stalePreviousAvID) ? stalePreviousAvID : "")
Defensive patterns

Strategy: validation

Validate before calling

const ids = await getBoundAvIDs(blockID); if (previousAvID && !ids.includes(previousAvID)) throw new Error("previous view not bound: " + previousAvID);

Type guard

const isValidPrevious = (ids, prev) => !prev || ids.includes(prev);

Try / catch

try { await bind(avID, prev); } catch (e) { if (String(e).includes("previous attribute view")) await bind(avID, ""); else throw e; }

Prevention

When it happens

Trigger: Calling the bind/reorder attribute view API with a non-empty previousAvID that is not among the block's currently bound attribute view IDs.

Common situations: Plugin passes a previousAvID from a different block or a removed view; UI saved a stale 'insert after' reference; view list changed between read and write.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/bd2a7b43e405381b. Report an issue: GitHub.