Skip to content

HMR errors inconsistently sent to multiple tabs #19710

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

Open
7 tasks done
infiton opened this issue Mar 24, 2025 · 1 comment · May be fixed by #19718
Open
7 tasks done

HMR errors inconsistently sent to multiple tabs #19710

infiton opened this issue Mar 24, 2025 · 1 comment · May be fixed by #19718
Labels
p2-edge-case Bug, but has workaround or limited in scope (priority)

Comments

@infiton
Copy link

infiton commented Mar 24, 2025

Describe the bug

This error is possible to reproduce on a brand new vite app.

Steps.

  1. create a vanilla vite app with npm create vite@latest
  2. run npm run dev
  3. Open the app in a tab
  4. introduce the following syntax error in counter.ts
export function setupCounter(element: HTMLButtonElement) {
  let counter = 0;
  const setCounter = (count: number) => {
    counter = count;
    element.innerHTML = `count is ${counter}`;
  };
  element.addEventListener("click", () => setCounter(counter + 1));
  setCounter(0);
  1. notice that you get an hmr overlay in first tab showing the error
  2. open the app in a second tab; you just get a white screen, until you hit refresh in the first tab, now you will see the hmr overlay in the second tab but not the first

Note that sometimes this doesn't happen, but 2 or 3 attempts of the above tab opening steps above should reproduce it. It's also possible to trigger it with two open tabs in the error state and refreshing one repeatedly; sometimes on refresh you get a white screen and the hmr error is not sent on the websocket until the other tab is refreshed.

Reproduction

https://vite.new/

Steps to reproduce

detailed in the above description

System Info

can reproduce on stackblitz and locally with 


  System:
    OS: macOS 14.5
    CPU: (10) arm64 Apple M1 Pro
    Memory: 116.09 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.9.0 - /opt/homebrew/bin/node
    Yarn: 1.22.22 - /opt/homebrew/bin/yarn
    npm: 10.8.3 - /opt/homebrew/bin/npm
    pnpm: 8.15.7 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 134.0.6998.118
    Safari: 17.5

Used Package Manager

pnpm

Logs

No response

Validations

@thegedge
Copy link

I was experiencing this too. Did some investigating and found that the issue is here:

socket.send(JSON.stringify({ type: 'connected' }))
if (bufferedError) {
socket.send(JSON.stringify(bufferedError))
bufferedError = null
}
})

bufferedError is set to null on a new connection, but that races with the code that sets bufferedError when sending the payload. At the time it sends out the error, there's typically only one of the clients connected. This comment

// On page reloads, if a file fails to compile and returns 500, the server
// sends the error payload before the client connection is established.
// If we have no open clients, buffer the error and send it to the next
// connected client.
let bufferedError: ErrorPayload | null = null

Seems to suggest it was intentional, given the singular "client". This was introduced in 23016ca, and I don't see any indication of exactly why we need to set bufferedError to null there.

I'm going to look into whether or not there's a better place for clearing out the buffered error, specifically when we know we've transitioned from an error state to a non-error state.

@sapphi-red sapphi-red added the p2-edge-case Bug, but has workaround or limited in scope (priority) label Mar 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p2-edge-case Bug, but has workaround or limited in scope (priority)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants