{"record":{"id":"79a7fabb093df6e5","repo":"siyuan-note/siyuan","slug":"attribute-view-sort-values-changed-retry-the-drag","errorCode":null,"errorMessage":"attribute view sort values changed; retry the drag","messagePattern":"attribute view sort values changed; retry the drag","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/attribute_view_row_sort.go","lineNumber":261,"sourceCode":"\t\t// 预览之后字段值可能变化，提交时再次校验，不能悄悄接受冲突的落点。\n\t\tcopyView, copyErr := cloneAttributeViewRowSort(attrView)\n\t\tif nil != copyErr {\n\t\t\treturn copyErr\n\t\t}\n\t\tcandidate := copyView.GetView(view.ID)\n\t\tsetAttributeViewRowOrder(candidate, change.RowOrder)\n\t\tcollections, renderErr := renderAttributeViewRowSortCollections(copyView, candidate, false)\n\t\tif nil != renderErr {\n\t\t\treturn renderErr\n\t\t}\n\t\tcollection := collections[*change.ValidateGroup]\n\t\tif nil == collection {\n\t\t\treturn av.ErrViewNotFound\n\t\t}\n\t\tordered := attributeViewRowSortIDs(collection.GetItems())\n\t\tav.Sort(collection.(av.Viewable), copyView)\n\t\tif !slices.Equal(ordered, attributeViewRowSortIDs(collection.GetItems())) {\n\t\t\treturn errors.New(\"attribute view sort values changed; retry the drag\")\n\t\t}\n\t}\n\tsetAttributeViewRowOrder(view, change.RowOrder)\n\treturn nil\n}\n\nfunc isAttributeViewRowOrderOperation(data any) bool {\n\tswitch value := data.(type) {\n\tcase *attributeViewRowOrderChange:\n\t\treturn nil != value\n\tcase map[string]any:\n\t\t_, ok := value[\"rowOrder\"]\n\t\treturn ok\n\t}\n\treturn false\n}\n\nfunc setAttributeViewRowOrder(view *av.View, order *attributeViewRowOrder) {","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/attribute_view_row_sort.go#L243-L279","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Reload the view, re-run the drag preview against current sort values, and retry the commit","Resolve/refresh the changed sort-key values first, then re-submit the row order","Accept that a manual drag on a sorted view may be overridden — re-apply the drag after values settle"],"exampleFix":"// before\napplyAttributeViewRowOrder(tx, avID, viewID, encodedFromPreview)\n// after\nif err := applyAttributeViewRowOrder(tx, avID, viewID, encodedFromPreview); err != nil {\n    // sort values changed: reload and rebuild the payload\n    view := loadView(avID, viewID)\n    applyAttributeViewRowOrder(tx, avID, viewID, buildFromView(view))\n}","handlingStrategy":"retry","validationCode":"const sortedKeys = getSortKeyValues(avID, viewID);\nif (!deepEqual(sortedKeys, previewSortKeyValues)) {\n  preview = rebuildDragPreview(avID, viewID); // values changed, redo preview\n}","typeGuard":null,"tryCatchPattern":"try {\n  await sortAttributeViewRow(avID, viewID, encodedChange);\n} catch (e) {\n  if (String(e.msg).includes(\"sort values changed\")) {\n    await reloadAttributeView(avID);\n    await retryDragCommit();\n  }\n}","preventionTips":["Commit drags promptly before background sort values refresh","Handle remote edits to sort-key columns by cancelling pending drags","Re-run the drag preview after any cell edit in sorted views"],"tags":["attribute-view","row-sort","optimistic-concurrency","retry"],"backgroundTag":"invalid-state-transition","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}