ianstormtaylor/slate · error · Error
Cannot move a path [${path}] to new path [${newPath}] becaus
Error message
Cannot move a path [${path}] to new path [${newPath}] because the destination is inside itself. What it means
move_node relocates a node to newPath. It throws when the destination newPath is inside the subtree of the node being moved (i.e. path is an ancestor of newPath), since moving a node into itself is impossible and would corrupt the tree.
Source
Thrown at packages/slate/src/interfaces/transforms/general.ts:136
`Cannot apply a "merge_node" operation at path [${path}] to nodes of different interfaces: ${Scrubber.stringify(
node
)} ${Scrubber.stringify(prev)}`
)
}
return replaceChildren(children, prevIndex, 2, newNode)
})
transformSelection = true
break
}
case 'move_node': {
const { path, newPath } = op
const index = path[path.length - 1]
if (Path.isAncestor(path, newPath)) {
throw new Error(
`Cannot move a path [${path}] to new path [${newPath}] because the destination is inside itself.`
)
}
const node = Node.get(editor, path)
modifyChildren(editor, Path.parent(path), children =>
removeChildren(children, index, 1)
)
// This is tricky, but since the `path` and `newPath` both refer to
// the same snapshot in time, there's a mismatch. After either
// removing the original position, the second step's path can be out
// of date. So instead of using the `op.newPath` directly, we
// transform `op.path` to ascertain what the `newPath` would be after
// the operation was applied.
const truePath = Path.transform(path, op)!
const newIndex = truePath[truePath.length - 1]View on GitHub (pinned to 72a37c701e)
Solutions
- Before moving, reject or adjust when Path.isAncestor(path, newPath) or Path.equals(path, newPath).
- In drop handlers, filter out drop targets that are descendants of the dragged node (a common UX rule: can't drop into self).
- If the move target was computed against a pre-move document, transform the newPath with the move_node operation first.
Example fix
// before
Transforms.moveNodes(editor, { at: path, to: newPath })
// after
if (!Path.isAncestor(path, newPath) && !Path.equals(path, newPath)) {
Transforms.moveNodes(editor, { at: path, to: newPath })
} Defensive patterns
Strategy: validation
Validate before calling
if (!Path.isAncestor(path, newPath) && !Path.equals(path, newPath)) {
Transforms.moveNodes(editor, { at: path, to: newPath })
} Type guard
function isSafeMove(path: Path, newPath: Path): boolean {
return !Path.isAncestor(path, newPath) && !Path.equals(path, newPath)
} Prevention
- In drag-and-drop, disallow drop targets inside the dragged node's subtree.
- Exclude descendant paths when computing move destinations.
- Transform newPath against prior operations when rebasing.
When it happens
Trigger: Applying move_node with Path.isAncestor(path, newPath) true — e.g. moving [0] to [0,0] (into its own child). Typically from computed newPaths in drag-and-drop or nested-list reordering logic that doesn't exclude the dragged node's own subtree.
Common situations: Drag-and-drop implementations that allow dropping a container into its own descendants; nested list/block reordering where the new index is computed from the drop target without subtree checks; collaborative ops rebased incorrectly.
Related errors
- Cannot resolve a Slate range from a DOM event: ${event}
- Unable to find the path for Slate node: ${Scrubber.stringify
- Could not set focus, editor seems stuck with pending operati
- Unable to find a host window element for this editor
- Cannot resolve a DOM node from Slate node: ${Scrubber.string
AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27).
Data as JSON: /api/errors/4da965909c2825aa.
Report an issue: GitHub.