ianstormtaylor/slate · error · Error

Cannot resolve a Slate range from DOM range: ${domRange}

Error message

Cannot resolve a Slate range from DOM range: ${domRange}

What it means

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.

Source

Thrown at packages/slate-dom/src/plugin/dom-editor.ts:1066

        } else {
          isCollapsed = domRange.isCollapsed
        }
      } else {
        anchorNode = domRange.startContainer
        anchorOffset = domRange.startOffset
        focusNode = domRange.endContainer
        focusOffset = domRange.endOffset
        isCollapsed = domRange.collapsed
      }
    }

    if (
      anchorNode == null ||
      focusNode == null ||
      anchorOffset == null ||
      focusOffset == null
    ) {
      throw new Error(
        `Cannot resolve a Slate range from DOM range: ${domRange}`
      )
    }

    // COMPAT: Firefox sometimes includes an extra \n (rendered by TextString
    // when isTrailing is true) in the focusOffset, resulting in an invalid
    // Slate point. (2023/11/01)
    if (
      IS_FIREFOX &&
      focusNode.textContent?.endsWith('\n\n') &&
      focusOffset === focusNode.textContent.length
    ) {
      focusOffset--
    }

    const anchor = DOMEditor.toSlatePoint(editor, [anchorNode, anchorOffset], {
      exactMatch,
      suppressThrow,

View on GitHub (pinned to 72a37c701e)

Solutions

  1. Check selection.rangeCount > 0 and that the editable contains the selection before converting
  2. Defer the read with requestAnimationFrame when handling selectionchange races
  3. Use DOMEditor.toSlateRange(editor, domRange, { suppressThrow: true }) and handle null
  4. Ensure focus is inside the editable before reading the native selection

Example fix

// before
const sel = window.getSelection()
const range = DOMEditor.toSlateRange(editor, sel.getRangeAt(0))
// after
const sel = window.getSelection()
if (sel && sel.rangeCount > 0) {
  const range = DOMEditor.toSlateRange(editor, sel.getRangeAt(0), { suppressThrow: true })
}
Defensive patterns

Strategy: validation

Validate before calling

const sel = window.getSelection()
if (sel && sel.rangeCount > 0 && DOMEditor.hasDOMNode(editor, sel.anchorNode)) {
  const range = DOMEditor.toSlateRange(editor, sel.getRangeAt(0), { suppressThrow: true })
}

Type guard

const hasNativeSelection = (sel: Selection | null): sel is Selection =>
  !!sel && sel.rangeCount > 0 && sel.anchorNode != null && sel.focusNode != null

Try / catch

try { DOMEditor.toSlateRange(editor, domRange) } catch (e) { if (/Cannot resolve a Slate range/.test(e.message)) return null; else throw e }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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