BookStackApp/BookStack · error · Error

Cannot call clear() on a frozen Lexical node map

Error message

Cannot call clear() on a frozen Lexical node map

What it means

Same frozen node-map dev guarantee as [147]: after pending state is frozen, calling .clear() on it throws 'Cannot call clear() on a frozen Lexical node map'. It exists to catch code clearing an editor state's node map that should be immutable once pending/committed.

Source

Thrown at resources/js/wysiwyg/lexical/core/LexicalUpdates.ts:469

    activeEditorState = previousActiveEditorState;
    isReadOnlyMode = previousReadOnlyMode;
    activeEditor = previousActiveEditor;
  }
}

function handleDEVOnlyPendingUpdateGuarantees(
  pendingEditorState: EditorState,
): void {
  // Given we can't Object.freeze the nodeMap as it's a Map,
  // we instead replace its set, clear and delete methods.
  const nodeMap = pendingEditorState._nodeMap;

  nodeMap.set = () => {
    throw new Error('Cannot call set() on a frozen Lexical node map');
  };

  nodeMap.clear = () => {
    throw new Error('Cannot call clear() on a frozen Lexical node map');
  };

  nodeMap.delete = () => {
    throw new Error('Cannot call delete() on a frozen Lexical node map');
  };
}

export function $commitPendingUpdates(
  editor: LexicalEditor,
  recoveryEditorState?: EditorState,
): void {
  const pendingEditorState = editor._pendingEditorState;
  const rootElement = editor._rootElement;
  const shouldSkipDOM = editor._headless || rootElement === null;

  if (pendingEditorState === null) {
    return;
  }

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Never clear an EditorState's _nodeMap; create a new state via parseEditorState/editor.setEditorState instead
  2. Refactor plugins to use public Lexical APIs for state changes
  3. Search codebase for direct _nodeMap usage and remove it
  4. If seen from a dependency, pin/update that dependency

Example fix

// before
editorState._nodeMap.clear();
// after
editor.setEditorState(editor.parseEditorState(serializedState));
Defensive patterns

Strategy: type-guard

Validate before calling

// To reset state, create a new one — never clear the map
if (needsReset) {
  editor.setEditorState(editor.parseEditorState(serialized));
}

Type guard

function canMutate(map: Map<string, unknown>): boolean {
  try { map.set('__t', 0); map.delete('__t'); return true; } catch { return false; }
}

Try / catch

try {
  resetEditorState(editor);
} catch (e) {
  if (/frozen Lexical node map/.test(e.message)) {
    editor.setEditorState(editor.parseEditorState(emptyDoc));
  }
}

Prevention

When it happens

Trigger: Any dev-mode path calling nodeMap.clear() on a pendingEditorState._nodeMap after parseEditorState/$commitPendingUpdates froze it — internal misuse or plugin code holding the map reference.

Common situations: Custom code attempting to reset editor state by clearing its node map; plugins copying state via internal APIs; dev-only invariant failures.

Related errors


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/3ff11e0c3328f6c0. Report an issue: GitHub.