siyuan-note/siyuan · error

source IDs must not be empty

Error message

source IDs must not be empty

What it means

ReorderDocs / ReorderDocTree validate their inputs through validateReorderArgs before touching any files. This error means the sourceIDs slice passed to the reorder operation was empty (nil or zero length). The reorder operation is defined only as 'move these one or more sibling docs before/after a target doc', so an empty source list is meaningless and rejected immediately.

Source

Thrown at kernel/model/file.go:2719

	}
	maps.Copy(fullSortIDs, sortIDs)
	if writeErr := writeSortConfMap(confPath, fullSortIDs); nil != writeErr {
		fileTreeSortLock.Unlock()
		return ret, writeErr
	}
	fileTreeSortLock.Unlock()

	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 {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Ensure the sources/sourceIDs array contains at least one document ID before calling ReorderDocs/ReorderDocTree
  2. Guard the caller: return early or no-op when the selection is empty instead of issuing the API call
  3. Check the frontend/plugin drag pipeline for losing the selection data before the request is sent

Example fix

// before
result, err := model.ReorderDocs(sourceIDs, targetID, "before")
// after
if len(sourceIDs) == 0 {
    return nil // nothing to reorder; skip the call
}
result, err := model.ReorderDocs(sourceIDs, targetID, "before")
Defensive patterns

Strategy: validation

Validate before calling

if len(sourceIDs) == 0 {
    return errors.New("reorder requires at least one source document ID")
}

Type guard

func hasSources(sourceIDs []string) bool { return len(sourceIDs) > 0 }

Try / catch

if err := validateSources(sourceIDs); err != nil {
    // handle locally; do not call ReorderDocs
    return err
}

Prevention

When it happens

Trigger: Calling the kernel API ReorderDocs([]string{}, "target-id", "before") / ReorderDocTree with an empty sources array; a frontend drag handler that computes the dragged block IDs after the DOM data was already cleared; mapping an empty selection into the API call.

Common situations: Plugin or client code building the request from a multi-select that was empty; a race where documents were removed from selection before the reorder request fired; scripts automating SiYuan that pass an unpopulated array variable.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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