{"record":{"id":"9bb1583c09dd9521","repo":"facebook/lexical","slug":"unexpected-delta-format","errorCode":null,"errorMessage":"Unexpected delta format","messagePattern":"Unexpected delta format","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/lexical-yjs/src/CollabElementNode.ts","lineNumber":273,"sourceCode":"            children.splice(nodeIndex + 1, 0, collabNode);\n            // The insert that triggers the text split might not be a text node. Need to keep a\n            // reference to the remaining text so that it can be added when we do create one.\n            pendingSplitText = spliceString(text, 0, splitIdx, '');\n          } else {\n            children.splice(nodeIndex, 0, collabNode);\n          }\n          if (\n            pendingSplitText !== null &&\n            collabNode instanceof CollabTextNode\n          ) {\n            // Found a text node to insert the pending text into.\n            collabNode._text = pendingSplitText + collabNode._text;\n            pendingSplitText = null;\n          }\n          currIndex += 1;\n        }\n      } else {\n        throw new Error('Unexpected delta format');\n      }\n    }\n  }\n\n  syncChildrenFromYjs(binding: Binding): void {\n    // Now diff the children of the collab node with that of our existing Lexical node.\n    const lexicalNode = this.getNode();\n    if (lexicalNode === null) {\n      // The Lexical node was concurrently removed (e.g. by a remote edit or undo)\n      // while we still have a pending change for it. There is nothing to reconcile\n      // into Lexical; this collab node will be cleaned up when its parent syncs.\n      return;\n    }\n\n    const key = lexicalNode.__key;\n    const prevLexicalChildrenKeys = $createChildrenArray(lexicalNode, null);\n    const nextLexicalChildrenKeys: NodeKey[] = [];\n    const lexicalChildrenKeysLength = prevLexicalChildrenKeys.length;","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/facebook/lexical/blob/76a22dcba981b46119fcec45f935270707e26a57/packages/lexical-yjs/src/CollabElementNode.ts#L255-L291","documentation":"CollabElementNode.applyChildrenYjsDelta maps Yjs delta operations ('insert' of Y.Text/Y.Map/Y.XmlElement or string, 'delete', 'retain') into Lexical mutations. Any delta component lacking a recognized 'insert'/'delete'/'retain' key indicates a malformed or foreign delta and the binding throws rather than corrupting the document.","triggerScenarios":"Applying a Yjs transaction whose delta contains an operation without exactly one of insert/delete/retain; feeding a hand-crafted or third-party-transformed Y.Text delta into syncLexical/updateFromYjs; version mismatches where a Yjs patch format changed.","commonSituations":"Custom middleware or CRDT proxies rewriting deltas; passing Y.Event deltas directly instead of using the library's observer pipeline; mixing y-protocols versions or applying deltas from an incompatible Yjs release.","solutions":["Verify the Yjs version matches what @lexical/yjs expects (check lockfiles for duplicate/hoisted yjs copies).","Do not fabricate or post-process deltas; rely on Y.Text.observe observers and let @lexical/yjs apply transactions itself.","Inspect the offending delta (log it before applyChildrenYjsDelta) to find who produced the malformed operation.","If using syncLexical/updateFromYjs manually, ensure deltas come straight from Yjs events and contain only insert/delete/retain."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"for (const d of delta) {\n  const keys = Object.keys(d).filter(k => ['insert','delete','retain'].includes(k));\n  if (keys.length !== 1) throw new Error('Malformed delta component: ' + JSON.stringify(d));\n}","typeGuard":"function isWellFormedDelta(delta: Y.YEvent['delta']): boolean {\n  return delta.every(d =>\n    ['insert', 'delete', 'retain'].filter(k => k in d).length === 1);\n}","tryCatchPattern":"try {\n  syncYjsChangesToLexical(provider, binding, true);\n} catch (e) {\n  if (e.message === 'Unexpected delta format') {\n    // resync from scratch\n    resetProviderState(provider, binding);\n  } else throw e;\n}","preventionTips":["Don't hand-craft or rewrite Yjs deltas — let Yjs observers feed @lexical/yjs","Pin a single yjs version across the app (watch for duplicate lockfile entries)","Log delta contents when wiring custom sync middleware","Test collaboration between all client versions before deploying custom nodes"],"tags":["collaboration","yjs","delta-format"],"backgroundTag":"invalid-yjs-delta","analyzedSha":"76a22dcba981b46119fcec45f935270707e26a57","analyzedAt":"2026-08-31T21:45:54.792Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}