facebook/lexical · warning
${name} should implement "importJSON" method to ensure JSON
Error message
${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected What it means
During createEditor node validation, a registered node class without its own static `importJSON` is warned about. Without importJSON, JSON serialization round-trips (editorState.toJSON → parseEditorState) and default HTML serialization will not restore this node correctly, so Lexical warns to keep serialization working as expected.
Source
Thrown at packages/lexical/src/LexicalEditor.ts:1041
`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')) {
console.warn(
`${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`,
);
}
}
}
const type = klass.getType();
const transforms = getTransformSetFromKlass(klass);
registeredNodes.set(type, {
exportDOM: html && html.export ? html.export.get(klass) : undefined,
klass,
replace,
replaceWithKlass,
sharedNodeState: createSharedNodeState(nodes[i]),
transforms,
});
}
}
const editor = new LexicalEditor(View on GitHub (pinned to 76a22dcba9)
Solutions
- Add `static importJSON(json: SerializedNode): ThisNode` that constructs the node via $create factory and calls node.updateFromJSON(json) (or applies each field).
- If serialization is irrelevant for this node, still provide a minimal importJSON for safety.
- Pair it with exportJSON to guarantee a complete round trip.
Example fix
// before
class MyNode extends TextNode {
static getType() { return 'my-node'; }
static clone(node: MyNode) { return new MyNode(node.__text, node.__key); }
}
// after
class MyNode extends TextNode {
static getType() { return 'my-node'; }
static clone(node: MyNode) { return new MyNode(node.__text, node.__key); }
static importJSON(json: SerializedMyNode): MyNode {
return $createMyNode(json.text).updateFromJSON(json);
}
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!Object.prototype.hasOwnProperty.call(MyNode, 'importJSON')) {
throw new Error('MyNode must implement static importJSON for serialization');
} Type guard
function hasImportJSON(klass: any): klass is {importJSON(json: any): any} {
return Object.prototype.hasOwnProperty.call(klass, 'importJSON') && typeof klass.importJSON === 'function';
} Prevention
- Implement static importJSON (and exportJSON) on every custom node, even if serialization seems unlikely.
- Round-trip test every node type: createEditorState -> toJSON -> parseEditorState and assert equality.
- Update node templates when upgrading Lexical as serialization expectations evolve.
When it happens
Trigger: Registering a custom node class via createEditor({nodes: [...]}) (or a nested editor) that lacks a static importJSON method; triggered right after the getType/clone checks for each node class.
Common situations: Custom nodes created before importJSON became expected; nodes only ever created programmatically and never deserialized, then later persisted; copy-pasted node templates missing importJSON.
Related errors
- ${name} must implement static "${method}" method
- Internal Lexical error: invariant() called without a message
- Invalid state key: ${key}
- [lexical] duplicate DOMImportRule name "${rule.name}" — keep
- message
AI-assisted analysis of facebook/lexical@76a22dcba9 (2026-08-31).
Data as JSON: /api/errors/5d8bf9e8696c7fff.
Report an issue: GitHub.