ianstormtaylor/slate · error · Error

Could not set focus, editor seems stuck with pending operati

Error message

Could not set focus, editor seems stuck with pending operations

What it means

Thrown by DOMEditor.focus after retrying (default 5 times, ~via setTimeout) while the editor still has pending operations, because setting selection/focus during in-flight changes is unstable. It indicates the editor is stuck with a non-empty editor.operations queue.

Source

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

  },

  focus: (editor, options = { retries: 5 }) => {
    // Return if already focused
    if (IS_FOCUSED.get(editor)) {
      return
    }

    // Return if no dom node is associated with the editor, which means the editor is not yet mounted
    // or has been unmounted. This can happen especially, while retrying to focus the editor.
    if (!EDITOR_TO_ELEMENT.get(editor)) {
      return
    }

    // Retry setting focus if the editor has pending operations.
    // The DOM (selection) is unstable while changes are applied.
    // Retry until retries are exhausted or editor is focused.
    if (options.retries <= 0) {
      throw new Error(
        'Could not set focus, editor seems stuck with pending operations'
      )
    }
    if (editor.operations.length > 0) {
      setTimeout(() => {
        DOMEditor.focus(editor, { retries: options.retries - 1 })
      }, 10)
      return
    }

    const el = DOMEditor.toDOMNode(editor, editor)
    const root = DOMEditor.findDocumentOrShadowRoot(editor)
    if (root.activeElement !== el) {
      // Ensure that the DOM selection state is set to the editor's selection
      if (editor.selection && root instanceof Document) {
        const domSelection = getSelection(root)
        const domRange = DOMEditor.toDOMRange(editor, editor.selection)
        domSelection?.removeAllRanges()

View on GitHub (pinned to 72a37c701e)

Solutions

  1. Call focus outside of change/onChange cycles (e.g. in useEffect after render)
  2. Check editor.operations.length before focusing and defer with setTimeout if non-empty
  3. Increase retries via DOMEditor.focus(editor, { retries: 10 })
  4. Audit custom plugins/normalizers that may throw mid-change and leave operations pending

Example fix

// before
editor.insertText('x')
DOMEditor.focus(editor) // inside same change
// after
editor.insertText('x')
setTimeout(() => DOMEditor.focus(editor))
Defensive patterns

Strategy: retry

Validate before calling

if (editor.operations.length === 0) {
  DOMEditor.focus(editor)
} else {
  setTimeout(() => DOMEditor.focus(editor, { retries: 10 }))
}

Type guard

null

Try / catch

try { DOMEditor.focus(editor, { retries: 10 }) } catch (e) { if (/Could not set focus/.test(e.message)) schedule another retry or surface a warning; else throw e }

Prevention

When it happens

Trigger: Calling editor.focus() repeatedly while editor.operations.length never drains — e.g. focus called inside a change loop, a bug elsewhere leaves operations on the queue, or overlapping asynchronous focus retries.

Common situations: Calling focus() inside onChange or a withOverride, an unhandled error aborting a change so operations never clear, or custom editor implementations that mutate editor.operations.

Related errors


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