ianstormtaylor/slate · error · Error
Cannot apply a "merge_node" operation at path [${path}] beca
Error message
Cannot apply a "merge_node" operation at path [${path}] because the root node cannot be merged. What it means
A merge_node operation joins a node with its previous sibling. The root node (path []) has no previous sibling and no parent to merge into, so Slate throws when merging at the root.
Source
Thrown at packages/slate/src/interfaces/transforms/general.ts:98
return {
...node,
text: before + text + after,
}
})
transformSelection = true
break
}
case 'merge_node': {
const { path } = op
const index = path[path.length - 1]
const prevPath = Path.previous(path)
const prevIndex = prevPath[prevPath.length - 1]
if (path.length === 0) {
throw new Error(
`Cannot apply a "merge_node" operation at path [${path}] because the root node cannot be merged.`
)
}
// Defend against malicious paths containing strings
if (typeof index !== 'number' || typeof prevIndex !== 'number')
throw new Error('Index must be number')
modifyChildren(editor, Path.parent(path), children => {
const node = children[index]
const prev = children[prevIndex]
let newNode: Descendant
if (Node.isText(node) && Node.isText(prev)) {
newNode = { ...prev, text: prev.text + node.text }
} else if (Node.isElement(node) && Node.isElement(prev)) {
newNode = { ...prev, children: prev.children.concat(node.children) }
} else {View on GitHub (pinned to 72a37c701e)
Solutions
- Guard before merging: only merge when path.length > 0 and Path.previous() would be valid.
- If you meant to merge the first child into something, merge the SECOND child into the first instead (merging always merges a node into its previous sibling).
- Check the value of at in Transforms.mergeNodes — it may be resolving to [] unexpectedly.
Example fix
// before
Transforms.mergeNodes(editor, { at: path }) // path may be []
// after
if (path.length > 0 && path[path.length - 1] > 0) {
Transforms.mergeNodes(editor, { at: path })
} Defensive patterns
Strategy: validation
Validate before calling
if (path.length > 0 && path[path.length - 1] > 0) {
Transforms.mergeNodes(editor, { at: path })
} Type guard
function isMergeablePath(path: Path): boolean {
return path.length > 0 && path[path.length - 1] > 0
} Prevention
- Always pass an explicit non-root at to Transforms.mergeNodes.
- Remember merging merges into the PREVIOUS sibling — first children can't merge.
- Log the resolved path before merging to catch collapses to [].
When it happens
Trigger: Applying or triggering merge_node with path === [] — e.g. Transforms.mergeNodes(editor, { at: [] }) or a computed path that collapses to the root, often after a path loses all segments during transforms.
Common situations: Custom delete/merge handlers that call Transforms.mergeNodes without an explicit non-root path; merging after other transforms shifted the target to the root; simulating Backspace at editor root.
Related errors
- Cannot set properties on the root node!
- Cannot get the next node from the root node!
- Cannot get the previous node from the root node!
- Cannot get the descendant node at path [${path}] because it
- Cannot apply an "insert_node" operation at path [${path}] be
AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27).
Data as JSON: /api/errors/59a48baadaf3cb71.
Report an issue: GitHub.