{"record":{"id":"2bd1d66e752061d2","repo":"ianstormtaylor/slate","slug":"cannot-resolve-a-slate-range-from-dom-range-dom","errorCode":null,"errorMessage":"Cannot resolve a Slate range from DOM range: ${domRange}","messagePattern":"Cannot resolve a Slate range from DOM range: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/slate-dom/src/plugin/dom-editor.ts","lineNumber":1066,"sourceCode":"        } else {\n          isCollapsed = domRange.isCollapsed\n        }\n      } else {\n        anchorNode = domRange.startContainer\n        anchorOffset = domRange.startOffset\n        focusNode = domRange.endContainer\n        focusOffset = domRange.endOffset\n        isCollapsed = domRange.collapsed\n      }\n    }\n\n    if (\n      anchorNode == null ||\n      focusNode == null ||\n      anchorOffset == null ||\n      focusOffset == null\n    ) {\n      throw new Error(\n        `Cannot resolve a Slate range from DOM range: ${domRange}`\n      )\n    }\n\n    // COMPAT: Firefox sometimes includes an extra \\n (rendered by TextString\n    // when isTrailing is true) in the focusOffset, resulting in an invalid\n    // Slate point. (2023/11/01)\n    if (\n      IS_FIREFOX &&\n      focusNode.textContent?.endsWith('\\n\\n') &&\n      focusOffset === focusNode.textContent.length\n    ) {\n      focusOffset--\n    }\n\n    const anchor = DOMEditor.toSlatePoint(editor, [anchorNode, anchorOffset], {\n      exactMatch,\n      suppressThrow,","sourceCodeStart":1048,"sourceCodeEnd":1084,"githubUrl":"https://github.com/ianstormtaylor/slate/blob/72a37c701e5da4bb13a305d416d9c070d19d3a45/packages/slate-dom/src/plugin/dom-editor.ts#L1048-L1084","documentation":"Thrown by DOMEditor.toSlateRange when the native DOM range's anchor/focus nodes or offsets are null/undefined, so no Slate range can be derived. Usually means the selection object was empty or collapsed to nothing at read time.","triggerScenarios":"Reading window.getSelection() when it contains no ranges (e.g. right after blur, or before the browser updates selection), or converting a DOMRange whose containers were detached from the document.","commonSituations":"onSelect/selectionchange handlers racing browser selection updates; reading selection after the editable was blurred or unmounted; Firefox-specific extra-newline offset issues preceding this guard.","solutions":["Check selection.rangeCount > 0 and that the editable contains the selection before converting","Defer the read with requestAnimationFrame when handling selectionchange races","Use DOMEditor.toSlateRange(editor, domRange, { suppressThrow: true }) and handle null","Ensure focus is inside the editable before reading the native selection"],"exampleFix":"// before\nconst sel = window.getSelection()\nconst range = DOMEditor.toSlateRange(editor, sel.getRangeAt(0))\n// after\nconst sel = window.getSelection()\nif (sel && sel.rangeCount > 0) {\n  const range = DOMEditor.toSlateRange(editor, sel.getRangeAt(0), { suppressThrow: true })\n}","handlingStrategy":"validation","validationCode":"const sel = window.getSelection()\nif (sel && sel.rangeCount > 0 && DOMEditor.hasDOMNode(editor, sel.anchorNode)) {\n  const range = DOMEditor.toSlateRange(editor, sel.getRangeAt(0), { suppressThrow: true })\n}","typeGuard":"const hasNativeSelection = (sel: Selection | null): sel is Selection =>\n  !!sel && sel.rangeCount > 0 && sel.anchorNode != null && sel.focusNode != null","tryCatchPattern":"try { DOMEditor.toSlateRange(editor, domRange) } catch (e) { if (/Cannot resolve a Slate range/.test(e.message)) return null; else throw e }","preventionTips":["Check rangeCount and editable containment before converting selection","Defer selection reads past selectionchange races (rAF)","Use suppressThrow for user-driven selection inspection"],"tags":["slate","selection","dom-range"],"backgroundTag":"empty-native-selection","analyzedSha":"72a37c701e5da4bb13a305d416d9c070d19d3a45","analyzedAt":"2026-08-27T23:04:51.145Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}