facebook/lexical · warning

Override for ${name} specifies 'replace' without 'withKlass'

Error message

Override for ${name} specifies 'replace' without 'withKlass'. 'withKlass' will be required in a future version.

What it means

When createEditor processes node overrides that use the legacy `replace` option without a `withKlass`, Lexical cannot statically know which class the override replaces, so it warns that 'withKlass' will become required. The override still works today, but the behavior is deprecated and will break in a future major version.

Source

Thrown at packages/lexical/src/LexicalEditor.ts:1022

      // For the side-effect of filling in the static methods
      void getStaticNodeConfig(klass);

      // Ensure custom nodes implement required methods and replaceWithKlass is instance of base klass.
      if (__DEV__) {
        // ArtificialNode__DO_NOT_USE can get renamed, so we use the type
        const name = klass.name;
        const nodeType =
          hasOwnStaticMethod(klass, 'getType') && klass.getType();

        if (replaceWithKlass) {
          invariant(
            replaceWithKlass.prototype instanceof klass,
            "%s doesn't extend the %s",
            replaceWithKlass.name,
            name,
          );
        } else if (replace) {
          console.warn(
            `Override for ${name} specifies 'replace' without 'withKlass'. 'withKlass' will be required in a future version.`,
          );
        }
        if (
          name !== 'RootNode' &&
          nodeType !== 'root' &&
          nodeType !== 'artificial' &&
          // This is mostly for the unit test suite which
          // uses LexicalNode in an otherwise incorrect way
          // by mocking its static getType
          klass !== LexicalNode
        ) {
          (['getType', 'clone'] as const).forEach(method => {
            if (!hasOwnStaticMethod(klass, method)) {
              console.warn(`${name} must implement static "${method}" method`);
            }
          });
          if (!hasOwnStaticMethod(klass, 'importJSON')) {

View on GitHub (pinned to 76a22dcba9)

Solutions

  1. Add withKlass to the override, naming the class being replaced: { replace: ..., withKlass: OriginalNode }.
  2. Where possible, replace the legacy override pattern with a proper node subclass registered via nodes: or an extension.
  3. Search the codebase for `replace:` node overrides and update each one.
  4. Watch the Lexical changelog for the version where withKlass becomes mandatory.

Example fix

// before
override: { replace: true, extend: klass }
// after
override: { replace: true, withKlass: klass, extend: klass }
Defensive patterns

Strategy: validation

Validate before calling

for (const [name, o] of Object.entries(nodeOverrides)) {
  if ('replace' in o && !('withKlass' in o)) {
    console.warn(`Override ${name} uses legacy replace; add withKlass before next major.`);
  }
}

Type guard

function hasWithKlass(o: object): o is { withKlass: Klass<LexicalNode> } {
  return 'withKlass' in o;
}

Try / catch

null

Prevention

When it happens

Trigger: createEditor (or buildEditorFromExtensions config) is given an entry like { replace: SomeNode, ... } (or override with replace: true) lacking the withKlass property, and validation reaches the `else if (replace)` branch.

Common situations: Upgrading Lexical and porting old node override configs; copy-pasting deprecated override examples from older docs; third-party extensions emitting legacy replace overrides.

Related errors


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