facebook/lexical · error

Unexpected delta format

Error message

Unexpected delta format

What it means

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.

Source

Thrown at packages/lexical-yjs/src/CollabElementNode.ts:273

            children.splice(nodeIndex + 1, 0, collabNode);
            // The insert that triggers the text split might not be a text node. Need to keep a
            // reference to the remaining text so that it can be added when we do create one.
            pendingSplitText = spliceString(text, 0, splitIdx, '');
          } else {
            children.splice(nodeIndex, 0, collabNode);
          }
          if (
            pendingSplitText !== null &&
            collabNode instanceof CollabTextNode
          ) {
            // Found a text node to insert the pending text into.
            collabNode._text = pendingSplitText + collabNode._text;
            pendingSplitText = null;
          }
          currIndex += 1;
        }
      } else {
        throw new Error('Unexpected delta format');
      }
    }
  }

  syncChildrenFromYjs(binding: Binding): void {
    // Now diff the children of the collab node with that of our existing Lexical node.
    const lexicalNode = this.getNode();
    if (lexicalNode === null) {
      // The Lexical node was concurrently removed (e.g. by a remote edit or undo)
      // while we still have a pending change for it. There is nothing to reconcile
      // into Lexical; this collab node will be cleaned up when its parent syncs.
      return;
    }

    const key = lexicalNode.__key;
    const prevLexicalChildrenKeys = $createChildrenArray(lexicalNode, null);
    const nextLexicalChildrenKeys: NodeKey[] = [];
    const lexicalChildrenKeysLength = prevLexicalChildrenKeys.length;

View on GitHub (pinned to 76a22dcba9)

Solutions

  1. Verify the Yjs version matches what @lexical/yjs expects (check lockfiles for duplicate/hoisted yjs copies).
  2. Do not fabricate or post-process deltas; rely on Y.Text.observe observers and let @lexical/yjs apply transactions itself.
  3. Inspect the offending delta (log it before applyChildrenYjsDelta) to find who produced the malformed operation.
  4. If using syncLexical/updateFromYjs manually, ensure deltas come straight from Yjs events and contain only insert/delete/retain.
Defensive patterns

Strategy: validation

Validate before calling

for (const d of delta) {
  const keys = Object.keys(d).filter(k => ['insert','delete','retain'].includes(k));
  if (keys.length !== 1) throw new Error('Malformed delta component: ' + JSON.stringify(d));
}

Type guard

function isWellFormedDelta(delta: Y.YEvent['delta']): boolean {
  return delta.every(d =>
    ['insert', 'delete', 'retain'].filter(k => k in d).length === 1);
}

Try / catch

try {
  syncYjsChangesToLexical(provider, binding, true);
} catch (e) {
  if (e.message === 'Unexpected delta format') {
    // resync from scratch
    resetProviderState(provider, binding);
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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