Skip to content

CommandManager keeps dispatching empty transactions, throwing Uncaught RangeError: Applying a mismatched transaction #3874

Description

@TeemuKoivisto

What’s the bug you are facing?

This is a preliminary bug report since I'm still figuring things out but I have already narrowed down the bug into here: https://github.com/ueberdosis/tiptap/blob/develop/packages/core/src/CommandManager.ts#L30

While I don't exactly understand what this is doing I just have to ask "what" and "why"? You are executing transactions as a side-effect of a getter? This just seems unideal.

So to give full context, I have a custom command defined by addCommands:

    addCommands(): AnnotationCommands {
      return {
        createAnnotation: () => ({ commands }) => {
            const { view, state } = this.editor;
            const { from, to } = view.state.selection;
            const textContent = state.doc.textBetween(from, to, "");

            return this.editor
              .commands.command((props) => {
                if (props.dispatch) {
                  const tr = props.tr
                    .addMark(from, to, this.type.create({ "draft-client-id": common.clientId }))
                    .setMeta('origin', 'createAnnotation')
                  props.dispatch(tr)
                  return true
                  // return this.editor.extensionManager.commands.setMark(this.name, {
                  //   "draft-client-id": common.clientId,
                  // })(props)
                }
                return false;
            })

        },

Which keeps throwing Uncaught RangeError: Applying a mismatched transaction errors where a second transaction is created with doc that is before this transaction is applied, causing this to trigger:

        if (!tr.before.eq(this.doc))
            throw new RangeError("Applying a mismatched transaction");

It's pretty insane bug since I can't find exactly where the additional dispatch is coming from. Probably CommandManager is doing some magic but alas, not in a right way.

EDIT: Okay, I figured it out. So you can't dispatch transactions yourself inside commands defined in addCommands. Although I'm pretty sure I used this.editor.chain which also broke so not sure exactly what's the core issue. Also, at times it seems to work okay when there's only single transaction so one could assume you were doing it correctly when in fact, you weren't, as the empty duplicate appears from somewhere and ProseMirror crashes.

So this works:

        createAnnotation: () => ({ chain }) => {
            return chain()
              .setMark(this.name, { "draft-client-id": common.clientId })
              .setMeta('origin', 'createAnnotation')
              .command(({ tr }) => {
                setAction(tr, EditorAclAction.isComment, true)
                return true
              })
        },

And yeah, this breaks as well:

            this.editor.chain()
              .setMark(this.name, {
                "draft-client-id": common.clientId,
              })
              .setMeta('hello', true)
              .run()

But please, is it possible to add either an error when you dispatch transaction yourself. Or, as I'd prefer myself, could the empty transaction be prevented as that's what is breaking things. Incase you want to enforce the use of tiptap CommandProps though you might have to add a watcher for dispatch instead that throws errors.

One thing I've started to do which I think is pretty useful is adding tr.setMeta('origin', myPluginKey) to all transactions that I dispatch manually. Dunno if that's doable here but it'd be nice to easily see who dispatched the original transaction since I couldn't figure it out at all.

EDIT EDIT: Okay apparently it says so here https://tiptap.dev/api/commands#chaining-inside-custom-commands that this doesn't work. Nice except maybe not enough obvious =).

Which browser was this experienced in? Are any special extensions installed?

Chrome 110
'@tiptap/core': ^2.0.0-beta.220
and all other extensions are ^2.0.0-beta.220 as well

How can we reproduce the bug on our side?

n/a

Can you provide a CodeSandbox?

nope

What did you expect to happen?

no errors :D

Anything to add? (optional)

No response

Did you update your dependencies?

  • Yes, I’ve updated my dependencies to use the latest version of all packages.

Are you sponsoring us?

  • Yes, I’m a sponsor. 💖

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: staleNo activity for an extended period, may be closed automatically

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions