ianstormtaylor/slate · error · Error
Expected index to be a number
Error message
Expected index to be a number
What it means
Thrown by getEditableChildAndIndex in slate-dom utils when the index passed to find an editable child is not a number. It is a defensive type check; the DOM point being normalized supplied a non-numeric offset.
Source
Thrown at packages/slate-dom/src/utils/dom.ts:162
return true
}
parent = parent.parentNode
}
return false
}
/**
* Get the nearest editable child and index at `index` in a `parent`, preferring
* `direction`.
*/
export const getEditableChildAndIndex = (
parent: DOMElement,
index: number,
direction: 'forward' | 'backward'
): [DOMNode, number] => {
if (typeof index !== 'number') {
throw new Error('Expected index to be a number')
}
const { childNodes } = parent
let child = childNodes[index]
let i = index
let triedForward = false
let triedBackward = false
// While the child is a comment node, or an element node with no children,
// keep iterating to find a sibling non-void, non-comment node.
while (
isDOMComment(child) ||
(isDOMElement(child) && child.childNodes.length === 0) ||
(isDOMElement(child) && child.getAttribute('contenteditable') === 'false')
) {
if (triedForward && triedBackward) {
break
}View on GitHub (pinned to 72a37c701e)
Solutions
- Ensure the DOMRange/DOMPoint you pass has explicit setStart/setEnd with numeric offsets
- Upgrade jsdom or polyfill Range/Selection APIs in tests
- Pass real browser selection objects rather than hand-made ranges
- Validate typeof domPoint.offset === 'number' before calling toSlatePoint
Example fix
// before
const r = document.createRange()
const p = DOMEditor.toSlatePoint(editor, { node: r.startContainer, offset: r.startOffset as any })
// after
const r = document.createRange()
r.setStart(textNode, 0)
r.setEnd(textNode, 0)
const p = DOMEditor.toSlatePoint(editor, { node: r.startContainer, offset: r.startOffset }) Defensive patterns
Strategy: type-guard
Validate before calling
const { node, offset } = domPoint
if (typeof offset !== 'number' || Number.isNaN(offset)) {
throw new Error('DOM point has no numeric offset — construct Range with setStart/setEnd')
} Type guard
const isWellFormedDomPoint = (p: { node: Node; offset: number }): boolean =>
p.node != null && typeof p.offset === 'number' && !Number.isNaN(p.offset) Try / catch
null
Prevention
- Always setStart/setEnd explicitly on created Ranges
- Keep jsdom up to date in tests
- Pass real Selection-derived points, not hand-built ones
When it happens
Trigger: normalizeDOMPoint receiving a DOM point whose offset is undefined/NaN — typically from a synthetic Range created incorrectly, or environments (older jsdom) returning undefined offsets.
Common situations: jsdom/test environments producing DOM points with undefined offsets; manually constructed document.createRange() with unset offsets passed to toSlatePoint/toSlateRange.
Related errors
- Cannot resolve a Slate range from a DOM event: ${event}
- Cannot resolve a DOM node from Slate node: ${Scrubber.string
- 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
AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27).
Data as JSON: /api/errors/7a5c448efb5830ad.
Report an issue: GitHub.