{"record":{"id":"d5e379d7bcf27b29","repo":"siyuan-note/siyuan","slug":"no-attribute-view-rows-selected","errorCode":null,"errorMessage":"no attribute view rows selected","messagePattern":"no attribute view rows selected","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/attribute_view_row_sort.go","lineNumber":172,"sourceCode":"\t}\n\treturn ret, nil\n}\n\nfunc attributeViewRowSortIDs(items []av.Item) []string {\n\tret := make([]string, 0, len(items))\n\tfor _, item := range items {\n\t\tret = append(ret, item.GetID())\n\t}\n\treturn ret\n}\n\nfunc moveAttributeViewSortedRows(ordered, selected []string, previousID, nextID string) ([]string, error) {\n\tselectedIDs := map[string]bool{}\n\tfor _, id := range selected {\n\t\tselectedIDs[id] = true\n\t}\n\tif 0 == len(selectedIDs) {\n\t\treturn nil, errors.New(\"no attribute view rows selected\")\n\t}\n\tvar moved, remaining []string\n\tfor _, id := range ordered {\n\t\tif selectedIDs[id] {\n\t\t\tmoved = append(moved, id)\n\t\t} else {\n\t\t\tremaining = append(remaining, id)\n\t\t}\n\t}\n\tif len(moved) != len(selectedIDs) {\n\t\treturn nil, errors.New(\"attribute view rows changed; retry the drag\")\n\t}\n\tif selectedIDs[nextID] || (\"\" == nextID && selectedIDs[previousID]) {\n\t\treturn slices.Clone(ordered), nil\n\t}\n\tindex := 0\n\tif \"\" != nextID {\n\t\tindex = slices.Index(remaining, nextID)","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/attribute_view_row_sort.go#L154-L190","documentation":"moveAttributeViewSortedRows builds a set of the selected row IDs and rejects the operation when that set is empty. An empty selection means there is nothing to move, so the row-sort drag operation is aborted with this error.","triggerScenarios":"Calling prepareAttributeViewRowSort (which delegates to moveAttributeViewSortedRows) with an empty `selected` slice — e.g. the frontend submitted a row drag payload with no row IDs, or the selection was cleared between drag start and commit.","commonSituations":"Frontend drag handlers sending stale/empty selection arrays; a script or plugin invoking the row sort API programmatically with an empty selected list; rows deleted concurrently so the selected-ID array arrived empty.","solutions":["Ensure the drag payload includes at least one selected row ID before calling the sort API","Re-fetch the current selection from the frontend state and retry the operation","Discard the stale drag operation and have the user re-perform the drag"],"exampleFix":"// before\nrows, err := moveAttributeViewSortedRows(ordered, selected, prevID, nextID)\n// after\nif len(selected) == 0 {\n    return nil // nothing to move; skip the sort request\n}\nrows, err := moveAttributeViewSortedRows(ordered, selected, prevID, nextID)","handlingStrategy":"validation","validationCode":"if (!selected || selected.length === 0) {\n    return; // nothing to move, skip the sort API call\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only invoke row-sort when at least one row is selected","Clear drag state when the selection changes","Guard programmatic API calls with a non-empty selection check"],"tags":["attribute-view","row-sort","empty-selection"],"backgroundTag":"empty-required-field","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"}