{"record":{"id":"fe6dad54d1f57fc0","repo":"ianstormtaylor/slate","slug":"cannot-get-the-ancestor-node-at-path-path-bec","errorCode":null,"errorMessage":"Cannot get the ancestor node at path [${path}] because it refers to a text node instead: ${Scrubber.stringify(\n          node\n        )}","messagePattern":"Cannot get the ancestor node at path \\[(.+?)\\] because it refers to a text node instead: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/slate/src/interfaces/node.ts","lineNumber":247,"sourceCode":"   */\n  string: (node: Node) => string\n\n  /**\n   * Return a generator of all leaf text nodes in a root node.\n   */\n  texts: (\n    root: Node,\n    options?: NodeTextsOptions\n  ) => Generator<NodeEntry<Text>, void, undefined>\n}\n\n// eslint-disable-next-line no-redeclare\nexport const Node: NodeInterface = {\n  ancestor(root: Node, path: Path): Ancestor {\n    const node = Node.get(root, path)\n\n    if (Node.isText(node)) {\n      throw new Error(\n        `Cannot get the ancestor node at path [${path}] because it refers to a text node instead: ${Scrubber.stringify(\n          node\n        )}`\n      )\n    }\n\n    return node\n  },\n\n  *ancestors(\n    root: Node,\n    path: Path,\n    options: NodeAncestorsOptions = {}\n  ): Generator<NodeEntry<Ancestor>, void, undefined> {\n    for (const p of Path.ancestors(path, options)) {\n      const n = Node.ancestor(root, p)\n      const entry: NodeEntry<Ancestor> = [n, p]\n      yield entry","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/ianstormtaylor/slate/blob/72a37c701e5da4bb13a305d416d9c070d19d3a45/packages/slate/src/interfaces/node.ts#L229-L265","documentation":"Node.ancestor(root, path) expects a path to an element (Ancestor = Editor | Element). If the node at that path is a text node, it cannot be an ancestor, so Slate throws with a stringified copy of the offending node. Note it throws on TEXT nodes specifically; paths pointing past the tree have their own errors.","triggerScenarios":"Calling Node.ancestor(editor, [0, 0]) where [0,0] is a text node; Editor.parent or other APIs that delegate to ancestor receiving a text-node path; passing an odd-path (leaf-level path) computed from a Range/Point offset path.","commonSituations":"Off-by-one path math when navigating from a selection point path to its parent element; assuming a path refers to an element when the document nests text differently than expected.","solutions":["Check the node kind first with Node.get + Node.isText (or Text.matches) before calling ancestor","For point/selection paths, use Editor.parent(editor, point.path) which correctly returns the element containing the text node, rather than ancestor on the text path itself","Fix path arithmetic — text nodes live at the deepest level, so their parent element is Path.parent(textPath)"],"exampleFix":"// before\nconst anc = Node.ancestor(editor, [0, 0]) // [0,0] is a text node -> throws\n\n// after\nconst anc = Node.ancestor(editor, Path.parent([0, 0])) // the element\n// or: const [[, el]] = Editor.parent(editor, [0, 0])","handlingStrategy":"type-guard","validationCode":"const node = Node.get(editor, path)\nif (!Node.isText(node)) {\n  const anc = Node.ancestor(editor, path)\n}","typeGuard":"const isAncestorPath = (root, path) =>\n  !Node.isText(Node.get(root, path))","tryCatchPattern":null,"preventionTips":["Use Editor.parent for selection-derived paths","Apply Path.parent to text paths before ancestor lookups","Check Node.isText before treating a node as an ancestor"],"tags":["slate","node-api","path","ancestor","type-mismatch"],"backgroundTag":"invalid-node-path","analyzedSha":"72a37c701e5da4bb13a305d416d9c070d19d3a45","analyzedAt":"2026-08-27T23:04:51.145Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}