siyuan-note/siyuan · error
duplicate source ID [%s]
Error message
duplicate source ID [%s]
What it means
validateReorderArgs rejects repeated IDs within sourceIDs using a seen-set. Each source document should appear exactly once in the move list; duplicates would double-insert the same document in reorderIDSequence and corrupt the resulting order. The error names the first duplicated ID.
Source
Thrown at kernel/model/file.go:2730
IncSync()
pushFiletreeSortChanged(sortIDs)
return
}
func validateReorderArgs(sourceIDs []string, targetID, position string) error {
if 1 > len(sourceIDs) {
return errors.New("source IDs must not be empty")
}
if "before" != position && "after" != position {
return fmt.Errorf("invalid reorder position [%s]", position)
}
seen := map[string]struct{}{}
for _, sourceID := range sourceIDs {
if sourceID == targetID {
return fmt.Errorf("target ID [%s] must not be included in source IDs", targetID)
}
if _, ok := seen[sourceID]; ok {
return fmt.Errorf("duplicate source ID [%s]", sourceID)
}
seen[sourceID] = struct{}{}
}
return nil
}
func isSortableDocument(tree *treenode.BlockTree) bool {
return nil != tree && tree.ID == tree.RootID && "d" == tree.Type && !IsBoxDoc(tree.BoxID, tree.RootID)
}
func loadSiblingCustomOrder(boxID, parentPath string, fullSortIDs map[string]int) (ret []string, err error) {
absParentPath := filepath.Join(util.DataDir, boxID, parentPath)
files, err := os.ReadDir(absParentPath)
if nil != err {
return nil, fmt.Errorf("read dir [%s] failed: %w", absParentPath, err)
}
for _, file := range files {
if file.IsDir() || !strings.HasSuffix(file.Name(), ".sy") {View on GitHub (pinned to 8641553a1f)
Solutions
- Deduplicate sourceIDs before the call, e.g. via a map or slices.Contains filter
- Fix the caller so each document is added to the sources list only once per operation
- If merging multiple selection sources, dedupe after the merge
Example fix
// before
err := model.ReorderDocs(sourceIDs, targetID, position) // may contain dupes
// after
seen := map[string]bool{}
unique := sourceIDs[:0]
for _, id := range sourceIDs {
if !seen[id] {
seen[id] = true
unique = append(unique, id)
}
}
err := model.ReorderDocs(unique, targetID, position) Defensive patterns
Strategy: validation
Validate before calling
seen := map[string]bool{}
for _, id := range sourceIDs {
if seen[id] {
return errors.New("duplicate source ID: " + id)
}
seen[id] = true
} Type guard
func hasNoDuplicates(ids []string) bool {
seen := make(map[string]struct{}, len(ids))
for _, id := range ids {
if _, ok := seen[id]; ok { return false }
seen[id] = struct{}{}
}
return true
} Try / catch
if !hasNoDuplicates(sourceIDs) {
sourceIDs = dedupe(sourceIDs) // dedupe before calling
} Prevention
- Deduplicate after merging selections from multiple origins
- Append each document ID once per operation, not once per drag event
- Cover duplicate handling with unit tests in selection-merge code
When it happens
Trigger: Calling ReorderDocs(["doc-a", "doc-a", "doc-b"], targetID, "before"); callers that merge selections from multiple origins without deduplicating (e.g. union of dragged + selected lists); loops that append an ID per event instead of once per document.
Common situations: Multi-select drag implementations that fire once per dragged item and concatenate IDs; bulk automation scripts processing duplicates from a stale index; event handlers accumulating selection state across drags.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- source IDs must not be empty
- target ID [%s] must not be included in source IDs
- wrong layout type
- filter nesting depth exceeds the maximum allowed
- invalid session id
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/3f9e4714ea0c2961.
Report an issue: GitHub.