siyuan-note/siyuan · error

attribute view [%s] is not bound

Error message

attribute view [%s] is not bound

What it means

When reordering the embedded attribute views of a block, the kernel locates the current position of avID in the bound-view ID list; if it is absent the unbind/reorder cannot proceed and this error is returned.

Source

Thrown at kernel/model/attribute_view.go:8619

	}
	return
}

func sortAttrViewBindingIDs(avIDs []string, avID, previousAvID string) (ret []string, err error) {
	ret = append([]string(nil), avIDs...)
	if avID == previousAvID {
		return
	}

	index := -1
	for i, id := range ret {
		if id == avID {
			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

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check the block's bound attribute view IDs before calling unbind/reorder
  2. Use the correct avID for the block being modified
  3. Skip unbind if the view was already unbound (make the call idempotent in the caller)

Example fix

// before
unbindAttrView(blockID, avID)
// after
if getBoundAvIDs(blockID).includes(avID) { unbindAttrView(blockID, avID) }
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

const isBound = (ids, avID) => Array.isArray(ids) && ids.includes(avID);

Try / catch

try { await unbind(avID); } catch (e) { if (String(e).includes("is not bound")) return; throw e; }

Prevention

When it happens

Trigger: Calling the unbind/reorder attribute view API with an avID that is not in the block's bound-view list (index stays -1).

Common situations: Double unbind of the same view; an avID from a deleted view block; plugin caches a view ID after the view was removed; copy/pasted avID from another block.

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/7cf78ebcaaa6507e. Report an issue: GitHub.