facebook/lexical · error

ListPlugin: ListNode and/or ListItemNode not registered on e

Error message

ListPlugin: ListNode and/or ListItemNode not registered on editor

What it means

ListPlugin requires both ListNode and ListItemNode to be registered on the editor, because its transforms and commands operate across list containers and their children. The plugin checks editor.hasNodes([ListNode, ListItemNode]) on mount and throws when either is absent. Lexical cannot handle node classes it was not configured with, so this is a fail-fast configuration check.

Source

Thrown at packages/lexical-react/src/LexicalListPlugin.ts:55

/**
 * Enables ordered, unordered, and check list support, registering the commands
 * and transforms that create and maintain {@link ListNode} and
 * {@link ListItemNode} structures. The editor must have both nodes registered.
 *
 * This is a legacy plugin. When building an editor with the extension API,
 * configure {@link ListExtension} instead.
 *
 * @returns `null`, this plugin renders no DOM of its own.
 */
export function ListPlugin({
  hasStrictIndent = false,
  shouldPreserveNumbering = false,
}: ListPluginProps): null {
  const [editor] = useLexicalComposerContext();

  useEffect(() => {
    if (!editor.hasNodes([ListNode, ListItemNode])) {
      throw new Error(
        'ListPlugin: ListNode and/or ListItemNode not registered on editor',
      );
    }
  }, [editor]);

  useEffect(() => {
    return mergeRegister(
      registerList(editor, {
        restoreNumbering: shouldPreserveNumbering,
      }),
      hasStrictIndent ? registerListStrictIndentTransform(editor) : () => {},
    );
  }, [editor, hasStrictIndent, shouldPreserveNumbering]);

  useList(editor);

  return null;
}

View on GitHub (pinned to 76a22dcba9)

Solutions

  1. Add both ListNode and ListItemNode from @lexical/list to the editor's nodes array
  2. Use the list extension with buildEditorFromExtensions to register both nodes
  3. Verify with editor.hasNodes([ListNode, ListItemNode]) before mounting the plugin

Example fix

// before
const initialConfig = {nodes: [ParagraphNode, TextNode, ListNode]}; // ListItemNode missing
<ListPlugin /> // throws

// after
import {ListNode, ListItemNode} from '@lexical/list';
const initialConfig = {nodes: [ParagraphNode, TextNode, ListNode, ListItemNode]};
<ListPlugin /> // ok
Defensive patterns

Strategy: validation

Validate before calling

import {ListNode, ListItemNode} from '@lexical/list';
if (!editor.hasNodes([ListNode, ListItemNode])) {
  throw new Error('Add ListNode and ListItemNode to your editor nodes config before using ListPlugin');
}

Type guard

function supportsLists(editor: LexicalEditor): boolean {
  return editor.hasNodes([ListNode, ListItemNode]);
}

Try / catch

try {
  if (!editor.hasNodes([ListNode, ListItemNode])) throw new Error('List nodes missing');
  // safe to use ListPlugin / list commands
} catch (e) {
  console.error('ListPlugin misconfigured:', e);
}

Prevention

When it happens

Trigger: Rendering <ListPlugin /> inside an editor created without ListNode or ListItemNode in the nodes array.

Common situations: Hand-assembling a nodes list and including only one of the two list nodes; copying list commands (insertUnorderedList) without registering nodes; moving off a preset bundle that previously registered both automatically.

Related errors


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