Yjs normalization inside ySyncPlugin transaction not propagating to ProseMirror

@Issa-Kakar Issa Kakar
Sat, 14 Feb 2026 02:52:14 +0000

I believe the binding wraps both directions of sync going PM→Yjs and Yjs→PM, so if one direction is running, the other direction is suppressed. Without it, you’d get PM changes → Yjs → observer fires → dispatches to PM → PM changes → Yjs → etc. etc. so its definitley not a bug, you would be stuck in a cycle for any Yjs mutations that happen synchronously during PM→Yjs sync. But either way the best way to handle this is to normalize before it reaches Yjs not afterwards. Normalizing in Yjs after the sync is going to 2x your doc updates, possibly more. I would normalize at the Prosemirror level, there’s an appendTransaction plugin for enforcing invariants. Then, for remote changes normalization happens inside of PM’s pipeline before the Yjs sync and not after, so it should be good both ways. You also could just try using setTimeout to delay the after transaction callback if you absolutley need to normalize in Yjs for some reason, but its much easier to make sure ysyncplugin only ever see the normalized state.