Failed to load module script
The browser asked for your app’s JavaScript and got an HTML page back, so it refused to run it and the page stayed blank.
Also appears as
- Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
- Loading module from “https://my-app.com/assets/index-B7xk2Lq9.js” was blocked because of a disallowed MIME type (“text/html”).
Prompt to fix it
After deploying, my app shows a blank page and the console says "Failed to load module script: Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of text/html". Find out why the built JavaScript URL returns HTML. Check base in vite.config, the host’s build command and output directory, rewrite rules, and any custom server’s static file setup. Set base to the absolute path the app is served from (avoid "./" with client-side routes) and make sure the fallback to index.html never answers for real files under /assets. Don’t hand-edit MIME types to force it.
Paste into Layerwise or any AI coding tool.
What it means
Vite builds your app into an index.html plus JavaScript files in assets/, loaded with <script type="module">. Browsers only run module scripts that the server labels as JavaScript. This error says the server labeled the file text/html: an HTML page arrived where JavaScript should be, usually a 404 page or your own index.html.
So the real question is why the script’s URL doesn’t point to a real file. Open the failed request in the Network tab. If its response is your app’s HTML, the path is wrong and a single-page app fallback answered in place of the missing file.
A common trap is base: './' in vite.config.ts. Relative paths work on the home page, but on a deep link like /dashboard/settings the browser asks for /dashboard/assets/index.js, which doesn’t exist. Apps with client-side routes need an absolute base, such as '/'.
Common causes
- The app is served from a subfolder, such as GitHub Pages at
/my-repo/, but was built with the defaultbaseof/. baseis set to./, so asset paths break on nested routes.- The host publishes the wrong folder, such as the project root instead of
dist, so the page requests the unbuilt/src/main.tsx. - A new deploy replaced the hashed files, and a cached
index.htmlor an open tab still asks for the old ones. - A custom server’s catch-all route returns
index.htmlfor every path, including/assets/*.
How to fix it
- Open DevTools → Network, reload, and click the failed
.jsrequest. Note its full URL and check the Response tab. - Compare that URL with the files in your build’s
dist/assetsfolder. - Set
baseinvite.config.tsto the path the app lives at:/for a domain root,/my-repo/for a GitHub Pages project site. Rebuild and redeploy. - Check the host’s settings: the build command should be
npm run buildand the output directorydist. - On a custom server, register static files before the catch-all, for example
app.use(express.static('dist'))above the route that returnsindex.html. - For tabs left open across a deploy, listen for Vite’s
vite:preloadErrorevent and reload the page.
Example fix
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
// The absolute path the app is served from.
// Use '/my-repo/' for a GitHub Pages project site.
base: '/'
});Related errors
All errorsFailed to fetch dynamically imported module
The browser asked for a piece of your app that no longer exists, usually because a new deploy replaced it while the page was open.
404 on page refresh
Your single-page app works from the home page, but the host has no file for deeper URLs, so reloads and shared links hit a 404.
Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Your code expected JSON, but the server sent back an HTML page, usually a 404 page or your app’s own index.html.
Failed to resolve import
Vite couldn’t find the file or package an import points to, so it can’t serve or build the page until the import matches something real.
Build with an agent that checks its work
The Layerwise agent clicks through the live preview and reads the console, so it catches errors before you do.