HMR Invalid URL, Hot Reloading Broken, and Patch Workarounds
Fix Expo Metro config HMR invalid URL errors and broken hot reloading. Covers ERR_INVALID_URL in metro HMR client, fast refresh not working, patch-package and yarn patch workarounds for metro and @expo/metro-config. Updated for Expo SDK 52+ in 2026.
On this page
While developing an Expo or React Native app, you may encounter an error where Hot Module Replacement (HMR) or Fast Refresh stops working with an invalid URL error. This usually appears as `ERR_INVALID_URL` in the Metro HMR client, a WebSocket connection failure, or Fast Refresh silently breaking so that changes require a full reload. These errors appear after upgrading Expo SDK, updating Metro bundler, changing your metro.config.js, running on a different network, or when your development URL contains characters that the HMR WebSocket client cannot parse.
The Error
You may also notice that Fast Refresh simply stops working without any visible error. You save a file, nothing updates, and you have to manually reload the app. The Metro terminal may show `Hot Module Replacement is disabled` or no HMR messages at all when you save files.
What Causes This Error
Metro HMR works by opening a WebSocket connection from the app on your device back to the Metro development server. The app constructs a WebSocket URL using the hostname and port of the server that served the JavaScript bundle. When the URL cannot be constructed correctly, HMR fails. The root causes are usually related to how Metro resolves and passes the development server hostname to the HMR client.
- Metro development server hostname is undefined or empty in the HMR client
- Custom metro.config.js overrides that break the internal server URL resolution
- Running Expo on a network where the local IP changes or is not reachable from the device
- A bug in a specific Metro or @expo/metro-config version that incorrectly formats the HMR URL
- Using a tunneling service (ngrok, Expo tunnel) that changes the URL format
- Windows-specific path issues where backslashes in URLs cause ERR_INVALID_URL
- Docker or WSL2 environment where the host IP is not accessible from the development server
- Conflicting metro.config.js plugins or transformers that override the server configuration
Fix 1: Set the Development Server Hostname Explicitly
The most common cause is Metro not knowing the correct hostname to use for the HMR WebSocket URL. You can force the hostname by setting the REACT_NATIVE_PACKAGER_HOSTNAME environment variable or passing it directly when starting Expo.
Replace 192.168.1.100 with your actual local IP address. This tells Metro exactly which hostname to use for the HMR WebSocket connection.
Fix 2: Clear Metro Cache and Restart
Metro caches the server configuration including the HMR URL. If you changed networks, updated metro.config.js, or upgraded Expo, the cached configuration may have the old or broken URL. Clearing all caches forces Metro to rebuild the configuration from scratch.
Fix 3: Patch Metro HMR Client for URL Bug
Some Metro versions have a bug where the HMR client receives an undefined hostname and tries to construct an invalid WebSocket URL. If Fixes 1 and 2 do not work, you can patch the Metro HMR client to handle the undefined hostname gracefully. Use patch-package to make this fix survive npm install.
Find the HMR client file in node_modules. The exact path depends on your Metro version.
Open the file and find where the WebSocket URL is constructed. Add a fallback for when the hostname is undefined.
After editing, create the patch and add the postinstall script.
Fix 4: Patch @expo/metro-config for URL Formatting Bug
In some Expo SDK versions, the @expo/metro-config package formats the development server URL incorrectly. This is different from the Metro HMR client bug. The fix is similar: find the file that constructs the URL, patch it, and use patch-package.
Fix 5: Use Yarn Patch Instead of patch-package
If you use Yarn 2 or above (Berry), you can use the built-in yarn patch command instead of patch-package. This creates patches that are managed by Yarn itself and do not require a postinstall script.
Fix 6: Switch Connection Type in Expo
Expo supports different connection types for communicating with the development server. If the default LAN connection is causing HMR issues, try switching to localhost or tunnel.
Fix 7: Windows-Specific Path Fix
On Windows, file paths use backslashes which can leak into URLs and cause ERR_INVALID_URL. If you are on Windows and see this error, the URL may contain backslashes like `ws://C:\Users\...` instead of forward slashes.
Fix 8: Docker and WSL2 Network Fix
In Docker containers or WSL2, the development server runs on a different network than the host machine. The device cannot reach the Metro server using the container internal IP. You need to expose the correct host IP to Metro.
Quick Diagnosis Checklist
- Check if the error shows undefined or empty hostname in the WebSocket URL
- Try setting REACT_NATIVE_PACKAGER_HOSTNAME to your local IP address
- Clear all caches: .expo, metro temp files, watchman, node_modules/.cache
- Restart Metro with npx expo start --clear
- Check if your device and development machine are on the same network
- Try switching connection type: --localhost, --tunnel, or LAN in Expo DevTools
- On Windows: check for backslashes in URL errors and try WSL2 or Git Bash
- In Docker or WSL2: expose port 8081 and set hostname to host.docker.internal
- If a specific Metro version is broken: patch the HMR client with patch-package
- Update Expo SDK and Metro: npx expo install expo@latest && npx expo install --fix
Final Working Commands
Official-Style Error Explanation
Expo Metro HMR invalid URL errors occur when the Metro development server cannot construct a valid WebSocket URL for the Hot Module Replacement client. Metro HMR works by opening a WebSocket connection from the app on the device back to the development server using the server hostname and port. When the hostname is undefined, empty, or contains invalid characters like Windows backslashes, the URL constructor throws ERR_INVALID_URL and HMR fails. The most common causes are network configuration issues where Metro cannot determine its own hostname, specific Metro or @expo/metro-config version bugs that format the URL incorrectly, Windows path characters leaking into URLs, and Docker or WSL2 environments where the internal network IP is not reachable from the device. The fix is usually to set REACT_NATIVE_PACKAGER_HOSTNAME to your local IP address and clear all Metro caches. For version-specific bugs, patching the Metro HMR client with patch-package or yarn patch provides a reliable workaround until the upstream fix is released.
FAQ
What is Metro HMR and why does it use WebSockets?
HMR (Hot Module Replacement) lets Metro push updated JavaScript modules to your app instantly when you save a file, without reloading the entire app. It uses a WebSocket connection from the app on your device back to the Metro server on your development machine. When this WebSocket URL is invalid, HMR stops working and you have to reload manually after every change.
Why does Fast Refresh stop working without any visible error?
When the WebSocket connection fails silently, Metro cannot push updates to the app. The app still runs but does not receive file change notifications. Check the Metro terminal output for WebSocket connection warnings. Also try saving a file and watching the Metro terminal. If it shows the file change but the app does not update, the WebSocket connection between the app and Metro is broken.
Why does setting REACT_NATIVE_PACKAGER_HOSTNAME fix this?
Metro auto-detects its hostname from the network interfaces on your machine. On some networks, VPNs, Docker containers, or WSL2 environments, this auto-detection fails and returns undefined or an unreachable IP. Setting the environment variable explicitly bypasses the auto-detection and tells Metro exactly which IP address to use for the WebSocket URL.
Is it safe to use patch-package to patch Metro?
Yes, for development workflow fixes like HMR. The patch only changes how the WebSocket URL is constructed, not how your app is bundled or shipped. The patch is applied locally in node_modules and does not affect your production build. Just make sure to remove the patch after upgrading to a Metro version that includes the upstream fix.
Why does this error only happen on Windows?
Windows uses backslashes in file paths. Some Metro code paths accidentally include file path strings in URL construction, which produces URLs like ws://C:\Users\... instead of ws://192.168.1.100:8081/hot. The Node.js URL constructor rejects backslashes and throws ERR_INVALID_URL. Using WSL2, setting REACT_NATIVE_PACKAGER_HOSTNAME, or running in Git Bash instead of CMD usually fixes this.
How do I make HMR work in Docker with Expo?
Expose port 8081 from the Docker container and set REACT_NATIVE_PACKAGER_HOSTNAME to host.docker.internal so the app on your device or emulator can reach the Metro server running inside the container. In docker-compose.yml, add ports 8081:8081 and environment REACT_NATIVE_PACKAGER_HOSTNAME=host.docker.internal.
Shahmeer Rizwan
Full-Stack Developer