siyuan-note/siyuan · warning

attribute view sort values changed; retry the drag

Error message

attribute view sort values changed; retry the drag

What it means

For views with active sorts, applyAttributeViewRowOrder replays the sorts on a cloned view and compares the resulting item order with the pre-sort order. If the sort changes the order, the underlying sort-key values changed since the drag preview (so accepting the drag would silently conflict with the sort), and the commit is rejected for retry.

Source

Thrown at kernel/model/attribute_view_row_sort.go:261

		// 预览之后字段值可能变化,提交时再次校验,不能悄悄接受冲突的落点。
		copyView, copyErr := cloneAttributeViewRowSort(attrView)
		if nil != copyErr {
			return copyErr
		}
		candidate := copyView.GetView(view.ID)
		setAttributeViewRowOrder(candidate, change.RowOrder)
		collections, renderErr := renderAttributeViewRowSortCollections(copyView, candidate, false)
		if nil != renderErr {
			return renderErr
		}
		collection := collections[*change.ValidateGroup]
		if nil == collection {
			return av.ErrViewNotFound
		}
		ordered := attributeViewRowSortIDs(collection.GetItems())
		av.Sort(collection.(av.Viewable), copyView)
		if !slices.Equal(ordered, attributeViewRowSortIDs(collection.GetItems())) {
			return errors.New("attribute view sort values changed; retry the drag")
		}
	}
	setAttributeViewRowOrder(view, change.RowOrder)
	return nil
}

func isAttributeViewRowOrderOperation(data any) bool {
	switch value := data.(type) {
	case *attributeViewRowOrderChange:
		return nil != value
	case map[string]any:
		_, ok := value["rowOrder"]
		return ok
	}
	return false
}

func setAttributeViewRowOrder(view *av.View, order *attributeViewRowOrder) {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Reload the view, re-run the drag preview against current sort values, and retry the commit
  2. Resolve/refresh the changed sort-key values first, then re-submit the row order
  3. Accept that a manual drag on a sorted view may be overridden — re-apply the drag after values settle

Example fix

// before
applyAttributeViewRowOrder(tx, avID, viewID, encodedFromPreview)
// after
if err := applyAttributeViewRowOrder(tx, avID, viewID, encodedFromPreview); err != nil {
    // sort values changed: reload and rebuild the payload
    view := loadView(avID, viewID)
    applyAttributeViewRowOrder(tx, avID, viewID, buildFromView(view))
}
Defensive patterns

Strategy: retry

Validate before calling

const sortedKeys = getSortKeyValues(avID, viewID);
if (!deepEqual(sortedKeys, previewSortKeyValues)) {
  preview = rebuildDragPreview(avID, viewID); // values changed, redo preview
}

Try / catch

try {
  await sortAttributeViewRow(avID, viewID, encodedChange);
} catch (e) {
  if (String(e.msg).includes("sort values changed")) {
    await reloadAttributeView(avID);
    await retryDragCommit();
  }
}

Prevention

When it happens

Trigger: Calling sortAttributeViewRow on a sorted view where a cell value used by the sort was modified between preview and commit — another client edited a sort-key field, a computed/rollup value refreshed, or sync updated rows.

Common situations: Collaborative editing where another user changes a date/number field used for sorting; background recalculation of relation/rollup values; sync applying remote edits to sort columns mid-drag.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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