Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Cannot read property 'matchesNode' of null (TipTap for React) #1451

Closed
chasinhues opened this issue Jun 11, 2021 · 38 comments
Closed
Labels
Type: Bug The issue or pullrequest is related to a bug

Comments

@chasinhues
Copy link

Description

Same issue as in #438. TypeError that crashes my app.

Steps to reproduce the bug

Happens on occasion when navigating to a page with a TipTap editor on it.

CodeSandbox

In the CSB below, run the tests, and observe the console spits out a bunch of these type errors for the browser. I don't know why it does this...

https://codesandbox.io/s/tiptap-prose-matchesnode-error-yhvdc

image

Expected behavior

No error.

Environment?

  • operating system: OSX
  • browser: N/A
  • mobile/desktop: N/A
  • tiptap version: @tiptap/core@^2.0.0-beta.65

Additional context

I tried to keep the CSB example above as close to my current code as possible, minus other third-party libraries that would unnecessarily bloat the example.

I am able to replicate the error consistently in my tests:

    Error: Uncaught [TypeError: Cannot read property 'matchesNode' of null]
        at reportException (/Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:62:24)
        at Timeout.task [as _onTimeout] (/Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/jsdom/lib/jsdom/browser/Window.js:521:9)
        at listOnTimeout (internal/timers.js:549:17)
        at processTimers (internal/timers.js:492:7) TypeError: Cannot read property 'matchesNode' of null
        at EditorView.updateStateInner (/Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/prosemirror-view/src/index.js:141:45)
        at EditorView.updateState (/Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/prosemirror-view/src/index.js:114:10)
        at Editor.dispatchTransaction (/Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/@tiptap/core/src/Editor.ts:299:15)
        at EditorView.dispatch (/Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/prosemirror-view/src/index.js:374:50)
        at Object.method [as focus] (/Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/@tiptap/core/src/CommandManager.ts:35:18)
        at /Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/@tiptap/core/src/Editor.ts:90:21
        at Timeout.task [as _onTimeout] (/Users/jasonhughes/sites/innovator-portal/innovator/client/node_modules/jsdom/lib/jsdom/browser/Window.js:516:19)
        at listOnTimeout (internal/timers.js:549:17)
        at processTimers (internal/timers.js:492:7)
@chasinhues chasinhues added Type: Bug The issue or pullrequest is related to a bug v2 labels Jun 11, 2021
@hanspagel
Copy link
Contributor

hanspagel commented Jun 11, 2021

Did you try upgrading all your dependencies? The core is at beta.81 already.

@MaximeHeckel
Copy link

Same issue on my end

Updated all my dependencies to the latests to try out, the issue still shows up.

For me it starts at "@tiptap/react": "^2.0.0-beta.43", which introduces the dependency array for the editor.

@chasinhues
Copy link
Author

chasinhues commented Jun 13, 2021

Thanks for the suggestion. Issue still persists using:
"@tiptap/core@^2.0.0-beta.81"
"@tiptap/react@^2.0.0-beta.46"
"@tiptap/starter-kit@^2.0.0-beta.77"

@obezzad
Copy link

obezzad commented Jun 24, 2021

@chasinhues is there any workaround?

@chasinhues
Copy link
Author

Not that I'm aware of

@obezzad
Copy link

obezzad commented Jun 24, 2021

@chasinhues I hope the following would help spotting the root cause.

This issue happens to me in editor.setContent() after hot-reload and when creating an editor dynamically, it also happens when dynamically adding multiple editors without delay. If I wait for a second after creating an editor before re-creating another one, it doesn't occur.

It seems that successive dynamic creation error is due to setTimeout(() => editor.createNodeViews(), 0) in EditorContent. I also suspect that this error causes the setContent() one too.

image

I added try-catch around setContent() with 3 retries separated by a delay of 100ms. However, the createNodeViews() does not seem to be catchable from the component.

Is there any chance of a hotfix to prevent this uncaught error from propagating since the software will be shipped soon :( ?

@jamesopti
Copy link

We're hitting this and have updated our dependencies to all the latest tiptap versions as of 2 days ago (see below):

This may be happening when we destroy the editor and then recreate it again. Is there any guidance on timing for destroying the editor before instantiating a new one?

➜  client git:(main) yarn info @tiptap/core @tiptap/react
├─ @tiptap/core@npm:2.0.0-beta.84
│  ├─ Version: 2.0.0-beta.84
│  │
│  └─ Dependencies
│     ├─ @types/prosemirror-commands@npm:^1.0.4 → npm:1.0.4
│     ├─ @types/prosemirror-inputrules@npm:^1.0.4 → npm:1.0.4
│     ├─ @types/prosemirror-keymap@npm:^1.0.4 → npm:1.0.4
│     ├─ @types/prosemirror-model@npm:^1.13.0 → npm:1.13.0
│     ├─ @types/prosemirror-schema-list@npm:^1.0.3 → npm:1.0.3
│     ├─ @types/prosemirror-state@npm:^1.2.6 → npm:1.2.6
│     ├─ @types/prosemirror-transform@npm:^1.1.3 → npm:1.1.3
│     ├─ @types/prosemirror-view@npm:^1.17.1 → npm:1.17.1
│     ├─ prosemirror-commands@npm:^1.1.9 → npm:1.1.9
│     ├─ prosemirror-inputrules@npm:^1.1.3 → npm:1.1.3
│     ├─ prosemirror-keymap@npm:^1.1.3 → npm:1.1.4
│     ├─ prosemirror-model@npm:^1.14.2 → npm:1.14.2
│     ├─ prosemirror-schema-list@npm:^1.1.4 → npm:1.1.4
│     ├─ prosemirror-state@npm:^1.3.4 → npm:1.3.4
│     ├─ prosemirror-transform@npm:^1.3.2 → npm:1.3.2
│     └─ prosemirror-view@npm:^1.18.7 → npm:1.18.7
│
└─ @tiptap/react@npm:2.0.0-beta.50
   ├─ Instances: 1
   ├─ Version: 2.0.0-beta.50
   │
   └─ Dependencies
      ├─ @tiptap/extension-bubble-menu@npm:^2.0.0-beta.23 → npm:2.0.0-beta.23
      ├─ @tiptap/extension-floating-menu@npm:^2.0.0-beta.17 → npm:2.0.0-beta.17
      └─ prosemirror-view@npm:^1.18.7 → npm:1.18.7

@philippkuehn
Copy link
Contributor

This patch should fix that error.

@obezzad
Copy link

obezzad commented Jun 30, 2021

@philippkuehn Thank you for the patch!
I noticed that the same error also occurs on setContent after React's Fast Refresh.

@chasinhues
Copy link
Author

Yeah I'm still noticing this as obezzad mentioned, even after upgrading to the patch with the fix.

I noticed that the same error also occurs on setContent after React's Fast Refresh.

@thatsjonsense
Copy link
Contributor

We were able to hack around this by adding checks for editor.isDestroyed in our useEffect hooks like so:
image

Could we update editor.commands to do this check automatically, and never try to run a command when the editor itself is destroyed? That might catch a lot of issues.

However, even after adding this, hot reload still triggered an error in the Yjs sync plugin, see screenshot below. It looks like that can also be suppressed by adding // @refresh reset at the top of the file where we load the Collaboration plugin. This is a NextJS directive, not sure if there are equivalents elsewhere.

Screen Shot 2021-07-06 at 2 21 29 PM

@obezzad
Copy link

obezzad commented Jul 7, 2021

@thatsjonsense Thank you for the workaround. I believe all the matchesNode errors are due editor.isDestroyed not checked. This may not be an issue in Vue, but React seems to work differently.

@philippkuehn Can you re-open this issue, or should we create another issue and refer to this one?

@martinemmert
Copy link

The CollaborationCursorPlugin throws the same error in some circumstances. We use the react TipTap package with the collab feature. Our editor can be opened and closed within our application - the open/close state is synced with all currently connected clients via websocket.

The error occurs when a user is still inside the editor, while the editor is closed by someone else. The root cause is the same as described here: #438 (comment)

@paolostyle
Copy link

paolostyle commented Sep 20, 2021

I have the same issue with BubbleMenu component that comes with @tiptap/react, it crashes when Fast Refresh is triggered. From what I understood from this conversation, the lack of editor.isDestroyed check causes that, so I changed this part in useEffect of BubbleMenu component (locally, in node_modules 😄) and it seems to work:

    if (!editor.isDestroyed) {
      editor.registerPlugin(BubbleMenuPlugin({
        pluginKey,
        editor,
        element: element.current as HTMLElement,
        tippyOptions,
        shouldShow,
      }))
    }

However it would probably make more sense to check it in registerPlugin considering a similar check is present in unregisterPlugin. Changing it in BubbleMenu seems like lower risk change, though. I can prepare a PR, but I'd rather have an opinion where it should be fixed as I'm completely unfamiliar with the codebase.

@longlongago2
Copy link

longlongago2 commented Oct 13, 2021

This patch should fix that error.

  useEffect(() => {
    if (editor && !editor.isDestroyed) {
      editor.chain().focus().setContent(content).run();
    }
  }, [content, editor]);

can solve this problem.

@thatsjonsense
Copy link
Contributor

Hey @philippkuehn, I think I've found a more general solution to this that prevents the error. A little hacky but let me know what you think

import { EditorView } from 'prosemirror-view'

EditorView.prototype.updateState = function updateState(state) {
  if (!this.docView) return // This prevents the matchesNode error on hot reloads
  this.updateStateInner(state, this.state.plugins != state.plugins)
}

@philippkuehn
Copy link
Contributor

@thatsjonsense Really a bit hacky :) Do you still see this error? Haven't seen it for ages.

@thatsjonsense
Copy link
Contributor

thatsjonsense commented Oct 29, 2021 via email

@jasonm
Copy link

jasonm commented Nov 27, 2021

I also see this regularly. I am using Snowpack with HMR and Fast Refresh. (https://www.snowpack.dev/concepts/hot-module-replacement) I have a React app with a component that wraps TipTap named <TipTapText/> in TipTapText.tsx. Each time I save that file and it HMR/Fast Refreshes, I see this error.

Adding the lines from @thatsjonsense 's comment above to TipTapText.tsx fixes the issue for me.

Versions:

 $ grep tiptap package.json
    "@tiptap/extension-collaboration": "^2.0.0-beta.31",
    "@tiptap/extension-collaboration-cursor": "^2.0.0-beta.31",
    "@tiptap/extension-placeholder": "^2.0.0-beta.44",
    "@tiptap/html": "^2.0.0-beta.142",
    "@tiptap/react": "^2.0.0-beta.95",
    "@tiptap/starter-kit": "^2.0.0-beta.145",

@raarts
Copy link

raarts commented May 3, 2022

Experienced this as well. Not hot-reloading. Also using multiple editors on the same page.
Hack by @thatsjonsense worked for me.

@gustavotoyota
Copy link

gustavotoyota commented Jun 20, 2022

I modified the code by @thatsjonsense to reuse the old updateState:

import { EditorView } from 'prosemirror-view';

const oldUpdateState = EditorView.prototype.updateState;

EditorView.prototype.updateState = function (state) {
  // This prevents the matchesNode error on hot reloads
  if (!this.docView) {
    return;
  }

  oldUpdateState.call(this, state);
};

This bug was apparently fixed in [email protected], but this same version introduced another issue:
yjs/y-prosemirror#117

So I had to downgrade to [email protected] and this problem still exists there.

@tguelcan
Copy link

tguelcan commented Jul 24, 2022

For me the error also came with a modal function where the editor was not visible.

I solved the problem by checking if the plugins are loaded.

export const resetContent = () => {
		if (editor.view.pluginViews.length) {
			editor.commands.clearContent();
		}
	};

@branlok
Copy link

branlok commented Sep 9, 2022

I'm still getting this issue in development, for me it occurs when my styled component wrapper gets resaved - it triggers the error. I've gotten around it by extracting editor explicitly into its own component and passing back to the parent component that has the styled component wrapper.

using:
vite": "^3.0.7",
"@tiptap/react": "^2.0.0-beta.114",
"@tiptap/starter-kit": "^2.0.0-beta.191",
"styled-components": "^5.3.5",

react-dom.development.js:22839 Uncaught TypeError: Cannot read properties of null (reading 'matchesNode')
    at EditorView.updateStateInner (index.js:4913:49)
    at EditorView.update (index.js:4868:14)
    at EditorView.setProps (index.js:4882:14)
    at Editor2.createNodeViews (Editor.ts:299:15)
    at PureEditorContent.init (EditorContent.tsx:67:14)
    at PureEditorContent.componentDidMount (EditorContent.tsx:42:10)
    at invokeLayoutEffectMountInDEV (react-dom.development.js:25133:22)
    at invokeEffectsInDev (react-dom.development.js:27351:11)
    at commitDoubleInvokeEffectsInDEV (react-dom.development.js:27327:5)
    at flushPassiveEffectsImpl (react-dom.development.js:27056:5)

@xiel
Copy link

xiel commented Sep 20, 2022

This error also seems to be triggered by StrictMode, because the component is immediatly unmounted and remounted.

@hrasoa
Copy link

hrasoa commented Oct 3, 2022

From time to time we are experiencing the same issue, this workaround #1451 (comment) works well, but is there any other recommendations since then? Thanks

@Gin-Quin
Copy link

It's not completely tiptap-relateded, but I had this issue because I implemented an asynchronous ProseMirror plugin.

If I closed the editor before the asynchronous call resolved, the program tried to update a view that didn't exist anymore.

My code was something like that:

asynchronousApiCall().then(data => {
  // this could happen after my editor is closed
  view.dispatch(view.state.tr.setMeta("call resolved", data)
})

And I added the following check:

asynchronousApiCall().then(data => {
  // check if the editor is still alive
  if (!(view as any)?.docView) return
  view.dispatch(view.state.tr.setMeta("call resolved", data)
})

@axelinternet
Copy link

I encountered this issue when adding dependencies to useEditor from @tiptap/react. I'm running "@tiptap/react": "^2.0.0-beta.199"

If I don't add the dependencies to the array I don't get this error when I have multiple editors on the same page. As I add deps to get it to react to being moved/destroyed I get this error. I

I used #1451 (comment) solution and removing the dependency array. This seems like a bug to me, I'm just getting a less granular solution to what I assume useEditor does under the hood.

@SalahAdDin
Copy link

I encountered this issue when adding dependencies to useEditor from @tiptap/react. I'm running "@tiptap/react": "^2.0.0-beta.199"

If I don't add the dependencies to the array I don't get this error when I have multiple editors on the same page. As I add deps to get it to react to being moved/destroyed I get this error. I

I used #1451 (comment) solution and removing the dependency array. This seems like a bug to me, I'm just getting a less granular solution to what I assume useEditor does under the hood.

It has been almost two years and there is no solution in sight.

@vaetas
Copy link

vaetas commented Feb 26, 2023

I've just followed the official documentation for installing TipTap into NextJS and got this bug. Latest TipTip and NextJS. I just copy pasted the example code without adding anything.

I tried all fixes and nothing seems to work. (I'm not sure if I was doing correctly.) Whenever I change something in the component I see this error in the browser.

Is there any other was I could make this work?

@tovaschreier
Copy link
Contributor

@vaetas Assuming your issue is caused by the same root cause as the issue I submitted, it was fixed in v2.0.0-beta.220!

@azjgard
Copy link

azjgard commented Apr 6, 2023

We were able to hack around this by adding checks for editor.isDestroyed in our useEffect hooks like so: image

Could we update editor.commands to do this check automatically, and never try to run a command when the editor itself is destroyed? That might catch a lot of issues.

However, even after adding this, hot reload still triggered an error in the Yjs sync plugin, see screenshot below. It looks like that can also be suppressed by adding // @refresh reset at the top of the file where we load the Collaboration plugin. This is a NextJS directive, not sure if there are equivalents elsewhere.

Screen Shot 2021-07-06 at 2 21 29 PM

This was ultimately the only thing that solved the problem for us. Echoing the question by @thatsjonsense: is this something that is possible for TipTap to check internally when commands are executing against an instance of the editor?

@SalahAdDin
Copy link

SalahAdDin commented Apr 7, 2023

We were able to hack around this by adding checks for editor.isDestroyed in our useEffect hooks like so: image
Could we update editor.commands to do this check automatically, and never try to run a command when the editor itself is destroyed? That might catch a lot of issues.
However, even after adding this, hot reload still triggered an error in the Yjs sync plugin, see the screenshot below. It looks like that can also be suppressed by adding // @refresh reset at the top of the file where we load the Collaboration plugin. This is a NextJS directive, not sure if there are equivalents elsewhere.
Screen Shot 2021-07-06 at 2 21 29 PM

This was ultimately the only thing that solved the problem for us. Echoing the question by @thatsjonsense: is this something that is possible for TipTap to check internally when commands are executing against an instance of the editor?

Did you open a PR for it?

I don't think they are planning to fix this.

@melodyclue
Copy link

This error also seems to be triggered by StrictMode, because the component is immediatly unmounted and remounted.

The remix app was also giving an error on every hot reload due to StrictMode, removing StrictMode worked fine.
But I guess that doesn't make sense for StrictMode, lol.

@actraiser
Copy link

I am using Remix v2 and have the same problem on every hot reload. I use useEditor(). I did not see a solution/workaround for people using that hook, maybe someone solved this though?

graphite-app bot pushed a commit to penxle/withglyph that referenced this issue Nov 10, 2023
1. localStorage에 postKind가 지정되어있지 않을 경우 postKind를 글 모드로 지정, 이 때 대소문자 오타가 있어 수정함 (article -> ARTICLE)
 
2. 글, 그림모드 전환 시 오류 발생
<img width="588" alt="image" src="https://github.com/penxle/penxle/assets/76952602/27089364-6f07-4e0f-8d10-79544ed3077c">


아래 내용 참고해 버블메뉴, 플로팅 메뉴 코드 수정함
ueberdosis/tiptap#1451
@fzsf163
Copy link

fzsf163 commented Feb 27, 2024

Hey @philippkuehn, I think I've found a more general solution to this that prevents the error. A little hacky but let me know what you think

import { EditorView } from 'prosemirror-view'

EditorView.prototype.updateState = function updateState(state) {
  if (!this.docView) return // This prevents the matchesNode error on hot reloads
  this.updateStateInner(state, this.state.plugins != state.plugins)
}

where do you put this line?
I am getting following error . Property 'docView' does not exist on type 'EditorView' & Property 'updateStateInner' is private and only accessible within class 'EditorView'

@whoselen
Copy link

Hey @philippkuehn, I think I've found a more general solution to this that prevents the error. A little hacky but let me know what you think

import { EditorView } from 'prosemirror-view'

EditorView.prototype.updateState = function updateState(state) {
  if (!this.docView) return // This prevents the matchesNode error on hot reloads
  this.updateStateInner(state, this.state.plugins != state.plugins)
}

where do you put this line? I am getting following error . Property 'docView' does not exist on type 'EditorView' & Property 'updateStateInner' is private and only accessible within class 'EditorView'

https://codesandbox.io/p/sandbox/tiptap-newline-error-kpgm8?file=%2Fsrc%2FApp.tsx%3A6%2C10-6%2C20

@kingsleydev19
Copy link

Experienced this as well. Not hot-reloading. Also using multiple editors on the same page. Hack by @thatsjonsense worked for me.

Hello, can you kindly explain to me exactly where I need to apply the codes? I am lost and I see this error.

@stetttho
Copy link

got the same error today when trying to update from 2.2.4 to 2.4.0 . workaround didn’t solve it, so switched back to 2.2.5, which is the latest version which works for me.

using multiple editors on the same page as others also mentioned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug The issue or pullrequest is related to a bug
Projects
None yet
Development

No branches or pull requests