siyuan-note/siyuan · error

Conf.Language(87)

Error message

Conf.Language(87)

What it means

ReorderDocTree rejects moves where a source document would be moved into itself or one of its descendants: the source shares the target's notebook and the target path equals the source path or lies under it. The message is the localized user-facing string Conf.Language(87) ('Cannot move to this location').

Solutions

  1. Choose a target outside the moved source's subtree
  2. In code, guard with a path-prefix check before calling reorderDocs
  3. If moving multiple documents, exclude ancestors of the target from sourceIDs

Example fix

// before
reorderDocs([parentID], childID, 'bottom')
// after
if (!targetPath.startsWith(parentPath.replace(/\.sy$/, '') + '/')) {
  reorderDocs([parentID], childID, 'bottom')
}
Defensive patterns

Strategy: validation

Validate before calling

function canMoveTo(sourcePath, targetPath) {
  return targetPath !== sourcePath && !targetPath.startsWith(sourcePath.replace(/\.sy$/, '') + '/')
}

Try / catch

try { await reorderDocs(sources, target, pos) } catch (e) { if (e.message === L(87)) notifyUser('Cannot move a document into its own subtree') }

Prevention

When it happens

Trigger: Calling ReorderDocTree where source.BoxID == target.BoxID and target.Path == source.Path or target.Path starts with source.Path minus the .sy suffix plus '/'.

Common situations: UI drag dropping a parent document onto its own child; scripted reorders computing a target inside the moved subtree.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/0ac4c0882400dfeb. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/file_tree_reorder.go:157

	}
	siblingIDs, err := loadSiblingCustomOrder(box.ID, parentDir, existingSorts)
	if err != nil {
		return nil, err
	}
	for _, id := range siblingIDs {
		if byID[id] == nil {
			return nil, fmt.Errorf("document [%s] could not be read", id)
		}
	}
	var fromPaths []string
	for _, id := range sourceIDs {
		source := treenode.GetBlockTree(id)
		if !isSortableDocument(source) || Conf.Box(source.BoxID) == nil {
			return nil, fmt.Errorf("source document [%s] is unavailable", id)
		}
		if source.BoxID == target.BoxID && (target.Path == source.Path ||
			strings.HasPrefix(target.Path, strings.TrimSuffix(source.Path, ".sy")+"/")) {
			return nil, errors.New(Conf.Language(87))
		}
		if byID[id] != nil {
			continue
		}
		sourceParent := path.Dir(source.Path)
		if sourceParent != "/" {
			sourceParent += ".sy"
		}
		sourceDocs, _, loadErr := ListDocTree(source.BoxID, sourceParent, util.SortModeCustom, false, true, int(^uint(0)>>1))
		if loadErr != nil {
			return nil, loadErr
		}
		for _, doc := range sourceDocs {
			if doc.ID == id {
				byID[id] = doc
				break
			}
		}

View on GitHub (pinned to 9f775e8a12)