{"record":{"id":"7a5c448efb5830ad","repo":"ianstormtaylor/slate","slug":"expected-index-to-be-a-number","errorCode":null,"errorMessage":"Expected index to be a number","messagePattern":"Expected index to be a number","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/slate-dom/src/utils/dom.ts","lineNumber":162,"sourceCode":"      return true\n    }\n    parent = parent.parentNode\n  }\n  return false\n}\n\n/**\n * Get the nearest editable child and index at `index` in a `parent`, preferring\n * `direction`.\n */\n\nexport const getEditableChildAndIndex = (\n  parent: DOMElement,\n  index: number,\n  direction: 'forward' | 'backward'\n): [DOMNode, number] => {\n  if (typeof index !== 'number') {\n    throw new Error('Expected index to be a number')\n  }\n\n  const { childNodes } = parent\n  let child = childNodes[index]\n  let i = index\n  let triedForward = false\n  let triedBackward = false\n\n  // While the child is a comment node, or an element node with no children,\n  // keep iterating to find a sibling non-void, non-comment node.\n  while (\n    isDOMComment(child) ||\n    (isDOMElement(child) && child.childNodes.length === 0) ||\n    (isDOMElement(child) && child.getAttribute('contenteditable') === 'false')\n  ) {\n    if (triedForward && triedBackward) {\n      break\n    }","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/ianstormtaylor/slate/blob/72a37c701e5da4bb13a305d416d9c070d19d3a45/packages/slate-dom/src/utils/dom.ts#L144-L180","documentation":"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.","triggerScenarios":"normalizeDOMPoint receiving a DOM point whose offset is undefined/NaN — typically from a synthetic Range created incorrectly, or environments (older jsdom) returning undefined offsets.","commonSituations":"jsdom/test environments producing DOM points with undefined offsets; manually constructed document.createRange() with unset offsets passed to toSlatePoint/toSlateRange.","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"],"exampleFix":"// before\nconst r = document.createRange()\nconst p = DOMEditor.toSlatePoint(editor, { node: r.startContainer, offset: r.startOffset as any })\n// after\nconst r = document.createRange()\nr.setStart(textNode, 0)\nr.setEnd(textNode, 0)\nconst p = DOMEditor.toSlatePoint(editor, { node: r.startContainer, offset: r.startOffset })","handlingStrategy":"type-guard","validationCode":"const { node, offset } = domPoint\nif (typeof offset !== 'number' || Number.isNaN(offset)) {\n  throw new Error('DOM point has no numeric offset — construct Range with setStart/setEnd')\n}","typeGuard":"const isWellFormedDomPoint = (p: { node: Node; offset: number }): boolean =>\n  p.node != null && typeof p.offset === 'number' && !Number.isNaN(p.offset)","tryCatchPattern":"null","preventionTips":["Always setStart/setEnd explicitly on created Ranges","Keep jsdom up to date in tests","Pass real Selection-derived points, not hand-built ones"],"tags":["slate","dom","type-check","jsdom"],"backgroundTag":"invalid-dom-point-offset","analyzedSha":"72a37c701e5da4bb13a305d416d9c070d19d3a45","analyzedAt":"2026-08-27T23:04:51.145Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}