ianstormtaylor/slate · error · Error
Cannot resolve a DOM node from Slate node: ${Scrubber.string
Error message
Cannot resolve a DOM node from Slate node: ${Scrubber.stringify(node)} What it means
Thrown by DOMEditor.toDOMNode when no rendered DOM element exists for the given Slate node. The node-to-element map has no entry, meaning the node is not currently rendered (or not rendered by this editor).
Source
Thrown at packages/slate-dom/src/plugin/dom-editor.ts:568
if (!DOMEditor.hasTarget(editor, target)) return false
const slateNode = DOMEditor.toSlateNode(editor, target)
return Node.isElement(slateNode) && Editor.isVoid(editor, slateNode)
},
setFragmentData: (editor, data, originEvent) =>
editor.setFragmentData(data, originEvent),
toDOMNode: (editor, node) => {
const domNode =
node === editor
? EDITOR_TO_ELEMENT.get(editor)
: EDITOR_TO_KEY_TO_ELEMENT.get(editor)?.get(
DOMEditor.findKey(editor, node)
)
if (!domNode) {
throw new Error(
`Cannot resolve a DOM node from Slate node: ${Scrubber.stringify(node)}`
)
}
return domNode
},
toDOMPoint: (editor, point) => {
const [node] = Editor.node(editor, point.path)
const el = DOMEditor.toDOMNode(editor, node)
let domPoint: DOMPoint | undefined
// If we're inside a void node, force the offset to 0, otherwise the zero
// width spacing character will result in an incorrect offset of 1
if (Editor.void(editor, { at: point })) {
point = { path: point.path, offset: 0 }
}
View on GitHub (pinned to 72a37c701e)
Solutions
- Defer the DOM lookup to after render (requestAnimationFrame/setTimeout or useEffect)
- Re-resolve the node by path/key after edits instead of reusing old node objects
- If virtualizing, look up only nodes known to be in the viewport
- Check the node still exists: Node.has(editor, path) before calling
Example fix
// before
Transforms.insertNodes(editor, { text: 'hi' })
const el = DOMEditor.toDOMNode(editor, editor.children[0]) // too early
// after
requestAnimationFrame(() => {
const el = DOMEditor.toDOMNode(editor, editor.children[0])
}) Defensive patterns
Strategy: validation
Validate before calling
// after render commit:
requestAnimationFrame(() => {
try { const el = DOMEditor.toDOMNode(editor, node) } catch { /* not rendered */ }
}) Type guard
null
Try / catch
try { el = DOMEditor.toDOMNode(editor, node) } catch (e) { if (/Cannot resolve a DOM node/.test(e.message)) skip or re-resolve; else throw e } Prevention
- Defer toDOMNode until after React commits (useEffect/rAF)
- Don't virtualize away nodes you need DOM access to
- Re-resolve nodes by path after edits
When it happens
Trigger: Calling toDOMNode for a node that was deleted, not yet rendered (before React commits), rendered virtually (e.g. outside a windowed/virtualized list that Slate renders lazily), or belonging to another editor instance.
Common situations: Calling toDOMNode immediately after inserting a node in the same tick (before render), using virtualization where off-screen nodes have no DOM, or holding a stale node after normalization replaced it.
Related errors
- Cannot resolve a Slate range from a DOM event: ${event}
- Cannot resolve a Slate node from DOM node: ${domEl}
- Expected index to be a number
- Unable to find the path for Slate node: ${Scrubber.stringify
- Could not set focus, editor seems stuck with pending operati
AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27).
Data as JSON: /api/errors/b10de3964d659e73.
Report an issue: GitHub.