{"record":{"id":"58f52b0fb40b9e6c","repo":"facebook/lexical","slug":"internal-lexical-error-invariant-called-without","errorCode":null,"errorMessage":"Internal Lexical error: invariant() called without a message","messagePattern":"Internal Lexical error: invariant\\(\\) called without a message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/lexical-internal/src/invariant.ts","lineNumber":28,"sourceCode":"// if \"condition\" is false will throw an error. This function is special-cased\n// in flow itself, so we can't name it anything else.\n//\n// In a production build the `transformErrorMessages` Babel plugin replaces\n// every call site with a hoisted `if (!cond)` check plus a\n// `formatProdErrorMessage(code, ...args)` call, so this body is only reached\n// when the source is consumed without that transform (the `source` export\n// condition or an untransformed dev build). It must therefore stand on its\n// own: interpolate `%s` placeholders against args and throw.\nexport default function invariant(\n  cond?: boolean,\n  message = 'Internal Lexical error: invariant() called without a message',\n  ...args: string[]\n): asserts cond {\n  if (cond) {\n    return;\n  }\n\n  throw new Error(\n    args.reduce((msg, arg) => msg.replace('%s', String(arg)), message),\n  );\n}\n","sourceCodeStart":10,"sourceCodeEnd":32,"githubUrl":"https://github.com/facebook/lexical/blob/76a22dcba981b46119fcec45f935270707e26a57/packages/lexical-internal/src/invariant.ts#L10-L32","documentation":"Lexical's invariant(cond, message) helper throws a plain Error when its condition is falsy; when it is called without a message argument the error text falls back to the generic 'Internal Lexical error: invariant() called without a message'. This signals an assertion failure inside Lexical's internal code paths (e.g. $getHtmlContent, exportNodeToJSON, $handleTab callers listed) where an assumed precondition about the node tree or selection did not hold. It usually indicates a corrupted or unexpected editor state rather than an API misuse with a documented remedy.","triggerScenarios":"Any of the calling APIs ($getHtmlContent, $getLexicalContent, exportNodeToJSON, $appendNodesToJSON, $getCodeLines, $handleTab) reaching an internal state that violates its assumptions — e.g. serializing a tree containing a node type that fails an internal assertion, or tab handling on a selection the code did not expect.","commonSituations":"Custom ElementNode/DecoratorNode implementations that break internal contracts (wrong return types from methods); operating on nodes not registered on the editor; version mismatches between @lexical packages after an upgrade; feeding hand-crafted JSON into $parseSerializedNode.","solutions":["Check whether a custom node's methods (createDOM, updateDOM, exportJSON, etc.) violate their contracts and fix the implementation","Ensure all node classes used in the document are registered on the editor","Align all @lexical/* package versions (stale/mismatched packages cause inconsistent invariants)","Reproduce with a minimal editor state and file an issue with the stack trace if it appears to be a Lexical bug"],"exampleFix":"// before\nexportJSON(): SerializedNode {return {type: 'my-node', ...};} // missing 'version', breaks exportNodeToJSON invariant\n\n// after\nexportJSON(): SerializedMyNode {return {...super.exportJSON(), type: 'my-node', version: 1};}","handlingStrategy":"try-catch","validationCode":"// validate node tree invariants before serialization\neditor.read(() => {\n  $dfs().forEach(({node}) => {\n    if (!node.getType()) throw new Error('Node missing type: ' + node.getKey());\n  });\n});","typeGuard":"function isSerializableNode(node: LexicalNode): node is LexicalNode & {exportJSON(): SerializedLexicalNode} {\n  return typeof (node as {exportJSON?: unknown}).exportJSON === 'function';\n}","tryCatchPattern":"try {\n  const html = $getHtmlContent();\n} catch (e) {\n  if (String(e).includes('Internal Lexical error')) {\n    console.error('Lexical invariant violated — check custom nodes and package versions', e);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Implement exportJSON/createDOM/updateDOM exactly per node contract (type, version fields)","Pin all @lexical/* packages to the same version","Register every node class present in the document on the editor","Never feed untrusted/hand-built node JSON without validating shape first"],"tags":["lexical","invariant","internal-error","serialization"],"backgroundTag":"internal-invariant-failure","analyzedSha":"76a22dcba981b46119fcec45f935270707e26a57","analyzedAt":"2026-08-31T21:45:54.792Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}