facebook/lexical · error

HashtagPlugin: HashtagNode not registered on editor

Error message

HashtagPlugin: HashtagNode not registered on editor

What it means

HashtagPlugin decorates hashtag text, which only works if the editor knows the HashtagNode class; Lexical editors can only process node types listed in their nodes config. The plugin checks editor.hasNodes([HashtagNode]) inside a useEffect and throws immediately if it is missing. This catches the configuration mistake at mount time instead of failing when a hashtag is typed.

Source

Thrown at packages/lexical-react/src/LexicalHashtagPlugin.ts:28

import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {type JSX, useEffect} from 'react';

/**
 * Enables hashtag support by transforming runs of text that begin with `#`
 * into {@link HashtagNode}s. The editor must have the {@link HashtagNode}
 * registered.
 *
 * This is a legacy plugin. When building an editor with the extension API,
 * configure {@link HashtagExtension} instead.
 *
 * @returns `null`, this plugin renders no DOM of its own.
 */
export function HashtagPlugin(): JSX.Element | null {
  const [editor] = useLexicalComposerContext();

  useEffect(() => {
    if (!editor.hasNodes([HashtagNode])) {
      throw new Error('HashtagPlugin: HashtagNode not registered on editor');
    }
    return registerLexicalHashtag(editor);
  }, [editor]);

  return null;
}

View on GitHub (pinned to 76a22dcba9)

Solutions

  1. Add HashtagNode (from @lexical/hashtag) to the editor's nodes array
  2. Use the hashtag extension via buildEditorFromExtensions so the node is registered
  3. Guard rendering: only mount HashtagPlugin when editor.hasNodes([HashtagNode]) is true

Example fix

// before
const initialConfig = {nodes: [ParagraphNode, TextNode]};
<LexicalComposer initialConfig={initialConfig}><HashtagPlugin /></LexicalComposer> // throws

// after
import {HashtagNode} from '@lexical/hashtag';
const initialConfig = {nodes: [ParagraphNode, TextNode, HashtagNode]};
<LexicalComposer initialConfig={initialConfig}><HashtagPlugin /></LexicalComposer> // ok
Defensive patterns

Strategy: validation

Validate before calling

import {HashtagNode} from '@lexical/hashtag';
if (!editor.hasNodes([HashtagNode])) {
  throw new Error('Add HashtagNode to your editor nodes config before using HashtagPlugin');
}

Type guard

function supportsHashtags(editor: LexicalEditor): boolean {
  return editor.hasNodes([HashtagNode]);
}

Try / catch

try {
  if (!editor.hasNodes([HashtagNode])) throw new Error('HashtagNode missing');
  // render/use plugin
} catch (e) {
  console.error('HashtagPlugin misconfigured:', e);
}

Prevention

When it happens

Trigger: Rendering <HashtagPlugin /> inside a LexicalComposer whose editor was created without HashtagNode in its nodes array.

Common situations: Building a custom editor configuration by hand and forgetting @lexical/hashtag's node; adding the plugin copied from the playground to an app with a minimal nodes list; switching from a preset (e.g. rich text extension bundle) to explicit node registration.

Related errors


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