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

  1. Check path.length >= 2 (or use Editor.above to confirm the node has a grandparent) before lifting
  2. In match functions, exclude root-level nodes (e.g. require n !== editor.children[i] or check path depth)
  3. 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

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


AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27). Data as JSON: /api/errors/e16d70b804377427. Report an issue: GitHub.