{"record":{"id":"e16d70b804377427","repo":"ianstormtaylor/slate","slug":"cannot-lift-node-at-a-path-path-because-it-ha","errorCode":null,"errorMessage":"Cannot lift node at a path [${path}] because it has a depth of less than \\`2\\`.","messagePattern":"Cannot lift node at a path \\[(.+?)\\] because it has a depth of less than \\\\`2\\\\`\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/slate/src/transforms-node/lift-nodes.ts","lineNumber":34,"sourceCode":"\n    if (!at) {\n      return\n    }\n\n    if (match == null) {\n      match = Location.isPath(at)\n        ? matchPath(editor, at)\n        : n => Node.isElement(n) && Editor.isBlock(editor, n)\n    }\n\n    const matches = Editor.nodes(editor, { at, match, mode, voids })\n    const pathRefs = Array.from(matches, ([, p]) => Editor.pathRef(editor, p))\n\n    for (const pathRef of pathRefs) {\n      const path = pathRef.unref()!\n\n      if (path.length < 2) {\n        throw new Error(\n          `Cannot lift node at a path [${path}] because it has a depth of less than \\`2\\`.`\n        )\n      }\n\n      const parentNodeEntry = Editor.node(editor, Path.parent(path))\n      const [parent, parentPath] = parentNodeEntry as NodeEntry<Ancestor>\n      const index = path[path.length - 1]\n      const { length } = parent.children\n\n      if (length === 1) {\n        const toPath = Path.next(parentPath)\n        Transforms.moveNodes(editor, { at: path, to: toPath, voids })\n        Transforms.removeNodes(editor, { at: parentPath, voids })\n      } else if (index === 0) {\n        Transforms.moveNodes(editor, { at: path, to: parentPath, voids })\n      } else if (index === length - 1) {\n        const toPath = Path.next(parentPath)\n        Transforms.moveNodes(editor, { at: path, to: toPath, voids })","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/ianstormtaylor/slate/blob/72a37c701e5da4bb13a305d416d9c070d19d3a45/packages/slate/src/transforms-node/lift-nodes.ts#L16-L52","documentation":"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.","triggerScenarios":"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.","commonSituations":"Toolbar 'lift block' button applied to a top-level paragraph; loops calling unwrap/lift in normalization; custom transforms lifting without checking depth.","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"],"exampleFix":"// before\nTransforms.liftNodes(editor, { at })\n\n// after\nif (Editor.hasPath(editor, at) && at.length >= 2) {\n  Transform.liftNodes(editor, { at })\n}","handlingStrategy":"type-guard","validationCode":"if (at.length >= 2) {\n  Transforms.liftNodes(editor, { at })\n} // else: top-level node, skip or change type instead","typeGuard":"const isLiftable = (p: Path): boolean => Array.isArray(p) && p.length >= 2","tryCatchPattern":null,"preventionTips":["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)"],"tags":["lift-nodes","path-depth","transform","slate"],"backgroundTag":"invalid-path-operation","analyzedSha":"72a37c701e5da4bb13a305d416d9c070d19d3a45","analyzedAt":"2026-08-27T23:04:51.145Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}