ianstormtaylor/slate · error · Error

Failed to attach MutationObserver, `node` is undefined

Error message

Failed to attach MutationObserver, `node` is undefined

What it means

RestoreDOM's MutationObserver wrapper throws when observe() is called before the restored DOM node ref exists (node.current is undefined). The observer must attach to the actual DOM element rendered by the <Slate> component; if the ref is not populated yet, restoration of DOM state cannot work.

Source

Thrown at packages/slate-react/src/components/restore-dom/restore-dom.tsx:40

type RestoreDOMProps = {
  children?: ReactNode
  receivedUserInput: RefObject<boolean>
  node: RefObject<HTMLDivElement>
}

// We have to use a class component here since we rely on `getSnapshotBeforeUpdate` which has no FC equivalent
// to run code synchronously immediately before react commits the component update to the DOM.
class RestoreDOMComponent extends Component<RestoreDOMProps> {
  static contextType = EditorContext
  context: ContextType<typeof EditorContext> = null

  private manager: RestoreDOMManager | null = null
  private mutationObserver: MutationObserver | null = null

  observe() {
    const { node } = this.props
    if (!node.current) {
      throw new Error('Failed to attach MutationObserver, `node` is undefined')
    }

    this.mutationObserver?.observe(node.current, MUTATION_OBSERVER_CONFIG)
  }

  componentDidMount() {
    const { receivedUserInput } = this.props
    const editor = this.context!

    this.manager = createRestoreDomManager(editor, receivedUserInput)
    this.mutationObserver = new MutationObserver(this.manager.registerMutations)

    this.observe()
  }

  getSnapshotBeforeUpdate() {
    const pendingMutations = this.mutationObserver?.takeRecords()
    if (pendingMutations?.length) {

View on GitHub (pinned to 72a37c701e)

Solutions

  1. Ensure the ref passed to RestoreDOM is attached to a rendered element before observe() runs (pass the same ref used by the editable component)
  2. Avoid consuming internal restore-dom components directly; use the shipped <Editable>/ <Slate> components
  3. If on a custom setup, upgrade slate-react to a matching version so internal component contracts line up

Example fix

// before
<RestoreDOM node={{ current: null }} ... />

// after
const ref = useRef<HTMLDivElement>(null)
// attach ref to the rendered editable element
<RestoreDOM node={ref} ... />
Defensive patterns

Strategy: validation

Validate before calling

useEffect(() => {
  if (!node.current) return
  observe()
}, [node.current])

Prevention

When it happens

Trigger: Rendering <RestoreDOM> without a valid node ref (or with a ref that is null on mount); using SlateReact internals outside the editable component; SSR where refs never populate; version mismatch between slate-react internals after upgrades.

Common situations: Custom editable components that reuse restore-dom.tsx with wrong props; upgrading slate-react across versions where RestoreDOM props changed; rendering the editor into a detached/hidden container where the ref is unset when observe runs.

Related errors


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