vitejs/vite · error · Error
rolldownOptions.input should not be an html file when…
Error message
rolldownOptions.input should not be an html file when building for SSR. Please specify a dedicated SSR entry.
What it means
When building for SSR (`environment.config.consumer === 'server'`), `resolveRolldownOptions` checks the resolved input: if it is a single string ending in `.html`, the build throws. HTML entries are for the browser; an SSR build needs a JavaScript/TS entry module, so the config is rejected with a directive to specify a dedicated SSR entry.
Solutions
- Set `build.ssr` to a server entry file: `build: { ssr: 'src/entry-server.ts' }`.
- Or set `build.rollupOptions.input` (the resolved input) to a `.js`/`.ts` server entry instead of `index.html`.
- Make sure `rolldownOptions.input` is not a `.html` path when targeting the SSR/server consumer.
Example fix
// before
build: { ssr: true } // falls back to index.html -> throws
// after
build: { ssr: 'src/entry-server.ts' } Defensive patterns
Strategy: validation
Validate before calling
function assertSsrEntryNotHtml(cfg: { build?: { ssr?: unknown }; rollupOptions?: { input?: unknown } }) {
const ssr = cfg.build?.ssr
const input = cfg.rollupOptions?.input
const resolvedInput = typeof ssr === 'string' ? ssr : input
if (resolvedInput != null && typeof resolvedInput === 'string' && resolvedInput.endsWith('.html')) {
throw new Error('SSR build input must not be an HTML file - set build.ssr to a .ts/.js entry')
}
} Type guard
function ssrEntryIsNotHtml(cfg: any): boolean {
const i = typeof cfg?.build?.ssr === 'string' ? cfg.build.ssr : cfg?.rollupOptions?.input
return !(typeof i === 'string' && i.endsWith('.html'))
} Prevention
- Set build.ssr to a server .ts/.js entry file, not the SPA index.html.
- Don't pass rolldownOptions.input as an HTML file for SSR/server consumer builds.
When it happens
Trigger: Setting `build.ssr: true` (or building an environment whose consumer is `server`) while the resolved input is an HTML file - typically the default `index.html` left because no SSR entry was configured. Also triggered by explicitly passing `rolldownOptions.input: 'index.html'` for an SSR build.
Common situations: Switching an app to SSR but forgetting to set `build.ssr` to a server entry path. Setting `ssr: true` (boolean) without an entry and relying on the default HTML input. Mixing SPA HTML entry with SSR build target.
Related errors
- Either "build.lib.entry" or the top-level "input" option is…
- No environment found
- `renderLegacyChunks` and `renderModernChunks` cannot be…
- Vite does not support "rolldownOptions.output.file". Please…
- @vitejs/plugin-legacy does not support library mode.
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/768909f032203b37.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/build.ts:628
const input = libOptions
? options.rolldownOptions.input ||
(typeof libOptions.entry === 'string'
? resolve(libOptions.entry)
: Array.isArray(libOptions.entry)
? libOptions.entry.map(resolve)
: Object.fromEntries(
Object.entries(libOptions.entry!).map(([alias, file]) => [
alias,
resolve(file),
]),
))
: typeof options.ssr === 'string'
? resolve(options.ssr)
: options.rolldownOptions.input ||
(topLevelInput ?? resolve('index.html'))
if (ssr && typeof input === 'string' && input.endsWith('.html')) {
throw new Error(
`rolldownOptions.input should not be an html file when building for SSR. ` +
`Please specify a dedicated SSR entry.`,
)
}
if (options.cssCodeSplit === false) {
const inputs =
typeof input === 'string'
? [input]
: Array.isArray(input)
? input
: Object.values(input)
if (inputs.some((input) => input.endsWith('.css'))) {
throw new Error(
`When "build.cssCodeSplit: false" is set, "rolldownOptions.input" should not include CSS files.`,
)
}
}
View on GitHub (pinned to b4d66fee14)