Skip to content

Conversation

@Aditya-Prakash14
Copy link

Description

This PR fixes an intermittent crash that causes the error Cannot read properties of undefined (reading 'call') during HMR and server restarts.

Fixes #21162

Problem

This error occurs intermittently and repeatedly, primarily when:

  • Making significant code changes (mass formatting or refactoring)
  • Switching branches
  • Modifying package.json

The error appears in both the browser and terminal, effectively stopping the HMR process and requiring a manual server restart. This is particularly common with Astro + Tailwind + React setups.

Root Cause

  1. vite-plugin-react intentionally removes its transform hook during the configResolved phase for performance optimization (source)
  2. During server restarts (especially triggered by package.json changes), the pluginContainer may iterate over cached plugin references where the transform hook has been dynamically deleted
  3. getHookHandler(plugin.transform) returns undefined, and attempting to call it throws the error

Credit to @sapphi-red for identifying the root cause.

Solution

Added a defensive check in pluginContainer.ts before calling the transform handler:

const handler = getHookHandler(plugin.transform)
if (!handler) {
  continue
}

Copy link
Member

@sapphi-red sapphi-red left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • During server restarts (especially triggered by package.json changes), the pluginContainer may iterate over cached plugin references where the transform hook has been dynamically deleted

Would you elaborate this?

Copy link
Member

@sapphi-red sapphi-red left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

@Aditya-Prakash14
Copy link
Author

Thanks for the question, happy to clarify.

What this sentence is trying to describe is a race between the dev server restart and in-flight transform calls. When package.json changes, Vite fully recreates the dev server: a new server instance (with fresh plugin instances) is created, the old server is closed, and properties from the new server are assigned back onto the existing server object. During this transition:

  • The old pluginContainer can still be running pending transform calls that started before the restart. These calls hold references to the old plugin objects.
  • Some plugins (like vite-plugin-react) intentionally delete or replace their transform hook during configResolved for performance reasons, so on those old plugin objects plugin.transform may already have been removed.

If pluginContainer iterates over its internal plugin list while one of those stale plugin objects no longer has a valid transform hook, getHookHandler(plugin.transform) returns undefined, and the subsequent handler.call(...) throws Cannot read properties of undefined (reading 'call'). The defensive check simply turns this into a no-op for that plugin in this edge case, letting the rest of the pipeline continue without crashing.

@sapphi-red
Copy link
Member

Each pluginContainer has a separate cache. So I don't think your explanation makes sense.

const utils = createPluginHookUtils(plugins)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot read properties of undefined (reading 'call')

2 participants