facebook/lexical · error

${error.toString()} Parent: ${dom.tagName}, new child: {tag:

Error message

${error.toString()} Parent: ${dom.tagName}, new child: {tag: ${replacementDOM.tagName} key: ${nextFirstChildKey}}, old child: {tag: ${lastDOM.tagName}, key: ${prevFirstChildKey}}.

What it means

During DOM reconciliation, Lexical catches an error thrown while replacing a child element and rethrows it enriched with context: the parent tag, the new child's tag and key, and the old child's tag and key. The embedded ${error.toString()} is the original reconciler failure; the wrapper exists to make the offending DOM nodes diagnosable.

Source

Thrown at packages/lexical/src/LexicalReconciler.ts:1618

      try {
        if (lastDOM.parentNode === dom) {
          dom.replaceChild(replacementDOM, lastDOM);
        } else {
          // lastDOM was reused as a descendant of replacementDOM (cross-parent
          // move, e.g. wrapping an image in a link). It's already detached
          // from `dom`, so just insert the replacement.
          slot.insertChild(replacementDOM);
        }
      } catch (error) {
        if (typeof error === 'object' && error != null) {
          const msg = `${error.toString()} Parent: ${
            dom.tagName
          }, new child: {tag: ${
            replacementDOM.tagName
          } key: ${nextFirstChildKey}}, old child: {tag: ${
            lastDOM.tagName
          }, key: ${prevFirstChildKey}}.`;
          throw new Error(msg);
        } else {
          throw error;
        }
      }
      $destroyNode(prevFirstChildKey, null);
    }
    const nextChildNode = activeNextNodeMap.get(nextFirstChildKey);
    if ($isTextNode(nextChildNode)) {
      if (subTreeTextFormat === null) {
        subTreeTextFormat = nextChildNode.getFormat();
        subTreeTextStyle = nextChildNode.getStyle();
        subTreeFirstTextKey = nextChildNode.__key;
      }
    }
  } else {
    const prevChildren = $createChildrenArray(prevElement, activePrevNodeMap);
    const nextChildren = $createChildrenArray(nextElement, activeNextNodeMap);
    invariant(

View on GitHub (pinned to 76a22dcba9)

Solutions

  1. Read the inner error.toString() in the message first — it is the root cause.
  2. Remove browser extensions or scripts that mutate the editor's DOM from outside Lexical APIs.
  3. Audit custom nodes' updateDOM/createDOM for incorrect tag reuse or mutation.
  4. Reproduce in development mode where Lexical runs with full warnings and more validation to get a clearer stack.

Example fix

// before (external mutation)
document.querySelector('[data-lexical-key="12"]').remove();
// after
editor.update(() => {
  $getNodeByKey('12').remove();
});
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  editor.update(() => applyChanges());
} catch (e) {
  if (e instanceof Error && e.message.includes('Parent:') && e.message.includes('old child:')) {
    console.error('Reconciliation mismatch (likely external DOM mutation):', e.message);
    editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined); // recover
  } else { throw e; }
}

Prevention

When it happens

Trigger: An error occurs in LexicalReconciler while replacing a first child during updateDomCreation/updateChildrenWithV2 logic — the caught `error` at line ~1618 is wrapped when a replacement DOM (replacementDOM) does not line up with the last DOM (lastDOM) being destroyed.

Common situations: Browser extensions mutating the editor DOM; external code directly manipulating the editor's DOM nodes; bugs in custom node updateDOM/exportDOM implementations; reconciliation races with scripts removing elements.

Related errors


AI-assisted analysis of facebook/lexical@76a22dcba9 (2026-08-31). Data as JSON: /api/errors/8200c1ae7cdba242. Report an issue: GitHub.