siyuan-note/siyuan · error

target ID [%s] must not be included in source IDs

Error message

target ID [%s] must not be included in source IDs

What it means

The reorder operation moves source documents relative to a target document, so the target itself must not be part of the moved set. validateReorderArgs iterates the sourceIDs and fails with this error if any source equals targetID. Allowing it would make 'insert [target] before target' ill-defined.

Source

Thrown at kernel/model/file.go:2727

	ret.Changed = true
	ret.Notebook = box.ID
	ret.ParentPath = parentPath
	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)

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Filter targetID out of the sourceIDs list before calling: sources := sources without targetID
  2. Validate in the caller and return a no-op when targetID appears among the sources (a drop onto itself does nothing)
  3. Fix the drag/selection code so the drop target is excluded from the dragged set

Example fix

// before
err := model.ReorderDocs(ids, targetID, position) // ids may contain targetID
// after
filtered := ids[:0]
for _, id := range ids {
    if id != targetID {
        filtered = append(filtered, id)
    }
}
err := model.ReorderDocs(filtered, targetID, position)
Defensive patterns

Strategy: validation

Validate before calling

for _, id := range sourceIDs {
    if id == targetID {
        return errors.New("target must not appear in source IDs")
    }
}

Type guard

func excludesTarget(sourceIDs []string, targetID string) bool {
    for _, id := range sourceIDs {
        if id == targetID { return false }
    }
    return true
}

Try / catch

if !excludesTarget(sourceIDs, targetID) {
    return nil // drop onto itself: treat as no-op
}

Prevention

When it happens

Trigger: Calling ReorderDocs(["doc-a", "doc-b"], "doc-a", "before") where one source ID equals the target ID; a frontend drag handler that appends the drop target into the dragged-IDs list; scripted multi-select that accidentally includes the anchor element.

Common situations: UI code selecting a range that includes the drop anchor; automation scripts filtering IDs incorrectly; plugins implementing custom drag-and-drop that include the hovered element among the dragged items.

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


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