Subscribe on changes!

Current instance is not unset after error in data() on SSR

avatar
Feb 16th 2023

Vue version

3.2.47

Link to minimal reproduction

https://stackblitz.com/edit/github-qw7apw-58cjm8

Steps to reproduce

Click 'Trigger error in data'. it will try to load a component where there is a JS error inside the data function on the component.

Then click 'click here to see stale instance' - it will perform a hard reload, calling getCurrentInstance() on the server and revealing that the instance was not unset.

What is expected?

I expect the current component instance to be unset if there is an error inside data.

What is actually happening?

The current component instance is not unset.

System Info

No response

Any additional comments?

This is very similar to https://github.com/vuejs/core/issues/6110 which has already been fixed. The difference is that the error happens in data instead of during rendering.

I had some troubles with our SSR setup and Pinia using the wrong instance after an error. Pinia looks for getCurrentInstance and uses that instance to inject the current pinia instance.

avatar
Feb 16th 2023

Similarly, throwing an error in created and then also throwing inside errorCaptured also leaves getCurrentInstance set. You can see this in the same reproducing example.

avatar
Feb 16th 2023

Here are two testcases that can be added to server-renderer/__tests__/render.spec.ts. (Not entirely sure that these test-cases are correct, or that this is the right place to put them. I trust the reproducing example more!)

      // #7733
      test('reset current instance after error in data', async () => {
        const prev = getCurrentInstance()
        expect(prev).toBe(null)
        try {
          await render(
              createApp({
                data() {
                  throw new Error();
                },
                template: `<div>hello</div>`
              })
          )
        } catch {}
        expect(getCurrentInstance()).toBe(null)
      })
    })

    test('reset current instance after error in errorCaptured', async () => {
      const prev = getCurrentInstance()
      expect(prev).toBe(null)
      try {
        await render(
            createApp({
              errorCaptured() {
                throw new Error();
              },
              template: `<div>hello</div>`,
              created() {
                throw new Error();
              }
            })
        )
      } catch {}
      expect(getCurrentInstance()).toBe(null)
    })