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

  1. Ensure the DOMRange/DOMPoint you pass has explicit setStart/setEnd with numeric offsets
  2. Upgrade jsdom or polyfill Range/Selection APIs in tests
  3. Pass real browser selection objects rather than hand-made ranges
  4. 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

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


AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27). Data as JSON: /api/errors/7a5c448efb5830ad. Report an issue: GitHub.