ianstormtaylor/slate · error · Error
Cannot find a descendant at path [${path}] in node: ${Scrubb
Error message
Cannot find a descendant at path [${path}] in node: ${Scrubber.stringify(
root
)} What it means
Node.get() walks the tree following the numeric path, but a segment cannot be resolved — either an index is out of range, an intermediate node is a text node (which has no children), or the path is longer than the tree depth. Slate throws because a missing node cannot be represented as undefined at this API level.
Source
Thrown at packages/slate/src/interfaces/node.ts:422
return { ...node, text: before }
})
}
if (Path.equals(path, start.path)) {
modifyLeaf(newRoot, path, node => {
const before = node.text.slice(start.offset)
return { ...node, text: before }
})
}
}
return newRoot.children
},
get(root: Node, path: Path): Node {
const node = Node.getIf(root, path)
if (node === undefined) {
throw new Error(
`Cannot find a descendant at path [${path}] in node: ${Scrubber.stringify(
root
)}`
)
}
return node
},
getIf(root: Node, path: Path): Node | undefined {
let node = root
for (let i = 0; i < path.length; i++) {
const p = path[i]
if (typeof p !== 'number') {
throw new Error('Got non-numeric path index')
}
View on GitHub (pinned to 72a37c701e)
Solutions
- Re-derive paths from the current document right before use (e.g. re-read selection or re-find the node) instead of caching paths across mutations.
- Check existence first with Node.has(root, path) before calling Node.get.
- If operating during transforms, defer lookups until after normalization completes (e.g. after ChangeEditor.flush or outside a withNormalized call).
- Validate depth: ensure the path length does not exceed tree depth via Node.ancestor or nodes() traversal.
Example fix
// before const node = Node.get(editor, stalePath) // after const node = Node.has(editor, stalePath) ? Node.get(editor, stalePath) : fallbackNode
Defensive patterns
Strategy: validation
Validate before calling
if (!Node.has(root, path)) { /* path is stale; re-derive it */ } Type guard
const safeGet = (root: Node, path: Path): Node | null => Node.has(root, path) ? Node.get(root, path) : null
Try / catch
try { Node.get(root, path) } catch (e) { if (e instanceof Error && e.message.startsWith('Cannot find a descendant')) { /* re-derive path */ } throw e } Prevention
- Never cache paths across mutations; re-read selection or re-traverse before lookup.
- Use Node.has as a pre-check whenever paths may be stale.
- Recompute paths after normalization/transforms complete.
When it happens
Trigger: Calling Node.get(editor, [1]) when the editor has only one child; calling Node.get with a stale path after a normalization/operation changed the tree; resolving a path that descends into a text node's 'children'.
Common situations: Using paths captured before an async operation (selection change, normalization, collaboritive edit) and applying them after the document mutated; desynchronized document between two editor instances; incorrect manual path arithmetic when building paths.
Related errors
- Cannot get the parent of path [${path}] because it does not
- Unable to find the path for Slate node: ${Scrubber.stringify
- Cannot get the next node from the root node!
- Cannot get the previous node from the root node!
- Cannot get the ancestor node at path [${path}] because it re
AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27).
Data as JSON: /api/errors/4576e31a6bfd7b0f.
Report an issue: GitHub.