ianstormtaylor/slate · error · Error

Slate hyperscript ranges must have both `<anchor />` and `<f

Error message

Slate hyperscript ranges must have both `<anchor />` and `<focus />` defined if one is defined, but you only defined `<anchor />`. For collapsed selections, use `<cursor />` instead.

What it means

Thrown by hyperscript's createEditor when an <anchor /> token was placed in the value but no matching <focus /> token exists. Slate ranges need both ends; hyperscript enforces the pair (or the collapsed <cursor /> alternative).

Source

Thrown at packages/slate-hyperscript/src/creators.ts:277

        }
      }

      for (const { ref = selection, offset } of getFoci(node)) {
        if (offset != null) {
          ref.focus = { path, offset }
        }
      }

      for (const { ref, offset } of getPoints(node)) {
        if (ref) {
          ref.offset = offset
          ref.path = path
        }
      }
    }

    if (selection.anchor && !selection.focus) {
      throw new Error(
        `Slate hyperscript ranges must have both \`<anchor />\` and \`<focus />\` defined if one is defined, but you only defined \`<anchor />\`. For collapsed selections, use \`<cursor />\` instead.`
      )
    }

    if (!selection.anchor && selection.focus) {
      throw new Error(
        `Slate hyperscript ranges must have both \`<anchor />\` and \`<focus />\` defined if one is defined, but you only defined \`<focus />\`. For collapsed selections, use \`<cursor />\` instead.`
      )
    }

    if (selectionChild != null) {
      editor.selection = selectionChild
    } else if (Range.isRange(selection)) {
      editor.selection = selection
    }

    return editor
  }

View on GitHub (pinned to 72a37c701e)

Solutions

  1. Add the matching <focus path={...} offset={...} /> token
  2. Replace the lone <anchor /> with <cursor /> for a collapsed selection

Example fix

// before
<editor>
  <paragraph><anchor path={[0,0]} offset={0} />hello</paragraph>
</editor>
// after
<editor>
  <paragraph><anchor path={[0,0]} offset={0} />hel<focus path={[0,0]} offset={3} />lo</paragraph>
</editor>
Defensive patterns

Strategy: validation

Validate before calling

// fixture invariant: count anchor and focus tokens
const anchors = countTokens(value, AnchorToken)
const focuses = countTokens(value, FocusToken)
if (anchors !== focuses) throw new Error('anchor/focus tokens must be paired')

Type guard

const isPairedSelectionTokens = (a: number, f: number): boolean => a === f

Try / catch

null

Prevention

When it happens

Trigger: Writing jsx(<editor><paragraph><anchor path={[0,0]} offset={0}/>text</paragraph></editor>) without a focus token.

Common situations: Authoring test editors where only the anchor was added, or where the focus token was accidentally removed during refactor.

Related errors


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