ianstormtaylor/slate · error · Error
Cannot lift node at a path [${path}] because it has a depth
Error message
Cannot lift node at a path [${path}] because it has a depth of less than \`2\`. What it means
liftNodes refuses to lift a node whose path depth is less than 2 — i.e. a top-level node (direct child of the editor root). Lifting would move the node above the document root, which is impossible, since the editor root is not a node in the document.
Source
Thrown at packages/slate/src/transforms-node/lift-nodes.ts:34
if (!at) {
return
}
if (match == null) {
match = Location.isPath(at)
? matchPath(editor, at)
: n => Node.isElement(n) && Editor.isBlock(editor, n)
}
const matches = Editor.nodes(editor, { at, match, mode, voids })
const pathRefs = Array.from(matches, ([, p]) => Editor.pathRef(editor, p))
for (const pathRef of pathRefs) {
const path = pathRef.unref()!
if (path.length < 2) {
throw new Error(
`Cannot lift node at a path [${path}] because it has a depth of less than \`2\`.`
)
}
const parentNodeEntry = Editor.node(editor, Path.parent(path))
const [parent, parentPath] = parentNodeEntry as NodeEntry<Ancestor>
const index = path[path.length - 1]
const { length } = parent.children
if (length === 1) {
const toPath = Path.next(parentPath)
Transforms.moveNodes(editor, { at: path, to: toPath, voids })
Transforms.removeNodes(editor, { at: parentPath, voids })
} else if (index === 0) {
Transforms.moveNodes(editor, { at: path, to: parentPath, voids })
} else if (index === length - 1) {
const toPath = Path.next(parentPath)
Transforms.moveNodes(editor, { at: path, to: toPath, voids })View on GitHub (pinned to 72a37c701e)
Solutions
- Check path.length >= 2 (or use Editor.above to confirm the node has a grandparent) before lifting
- In match functions, exclude root-level nodes (e.g. require n !== editor.children[i] or check path depth)
- Use a different transform for top-level nodes (e.g. setNodes to change type) instead of lifting
Example fix
// before
Transforms.liftNodes(editor, { at })
// after
if (Editor.hasPath(editor, at) && at.length >= 2) {
Transform.liftNodes(editor, { at })
} Defensive patterns
Strategy: type-guard
Validate before calling
if (at.length >= 2) {
Transforms.liftNodes(editor, { at })
} // else: top-level node, skip or change type instead Type guard
const isLiftable = (p: Path): boolean => Array.isArray(p) && p.length >= 2
Prevention
- Check path depth before lifting in toolbar handlers
- Exclude top-level nodes in match functions for liftNodes
- Test transforms against documents with minimal depth (single root-level node)
When it happens
Trigger: Transforms.liftNodes(editor, { at: [0] }) — lifting a top-level element; liftNodes with a match that matches root-level nodes; calling liftNodes repeatedly until nodes reach depth 1.
Common situations: Toolbar 'lift block' button applied to a top-level paragraph; loops calling unwrap/lift in normalization; custom transforms lifting without checking depth.
Related errors
- Cannot merge the node at path [${path}] with the previous si
- 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
AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27).
Data as JSON: /api/errors/e16d70b804377427.
Report an issue: GitHub.