vitejs/vite · error · Error
When "build.cssCodeSplit: false" is set…
Error message
When "build.cssCodeSplit: false" is set, "rolldownOptions.input" should not include CSS files.
What it means
Thrown when build.cssCodeSplit is disabled (false) yet one of the rolldownOptions.input entries points at a .css file. With cssCodeSplit off, Vite feeds CSS through the JS pipeline (moduleType '.css': 'js'), so a raw CSS entry produces an invalid JS module. The guard lives in build.ts where inputs are flattened from string/array/object forms before bundling.
Solutions
- Point rolldownOptions.input at the JS/TS entry that imports the CSS, not at the .css file directly.
- If you truly need a standalone CSS bundle, leave cssCodeSplit at its default (true) and import the stylesheet from JS so Vite extracts it.
- Remove the .css path from input and instead import it from your entry module.
Example fix
// before
build: {
cssCodeSplit: false,
rollupOptions: { input: 'src/styles.css' }
}
// after
build: {
cssCodeSplit: false,
rollupOptions: { input: 'src/entry.ts' } // entry.ts imports './styles.css'
} Defensive patterns
Strategy: validation
Validate before calling
function validateInput(input, cssCodeSplit) {
if (!cssCodeSplit) {
const inputs = Array.isArray(input) ? input
: typeof input === 'object' ? Object.values(input) : [input];
if (inputs.some((i) => String(i).endsWith('.css'))) {
return { ok: false, reason: 'input must not contain .css when cssCodeSplit is false' };
}
}
return { ok: true };
} Type guard
function isNonCssInput(input) {
const inputs = Array.isArray(input) ? input
: typeof input === 'object' && input !== null ? Object.values(input) : [input];
return inputs.every((i) => !String(i).endsWith('.css'));
} Prevention
- Always point build.rolldownOptions.input at JS/TS source files that import CSS, never at raw .css files.
- Audit rolldownOptions.input whenever you toggle build.cssCodeSplit.
When it happens
Trigger: Setting build.cssCodeSplit: false in vite.config while also listing a .css file under build.rolldownOptions.input (string, array, or object form). Happens most often when migrating an HTML-driven build to a CSS-only entry.
Common situations: Design-system or component-library builds that want a single bundled stylesheet and accidentally pass the .css path as the build entry instead of the .ts/.js source. Also seen when copy-pasting rolldownOptions.input from a pure-CSS pipeline.
Related errors
- Name in package.json is required if option…
- Vite does not support "rolldownOptions.output.file". Please…
- Environment " " is not defined in the config.
- Failed to load PostCSS config
- `input` cannot contain glob characters. They are reserved…
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/024c234125b5156b.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/build.ts:641
? 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.`,
)
}
}
const outDir = resolve(options.outDir)
// inject environment and ssr arg to plugin load/transform hooks
const plugins = environment.plugins.map((p) =>
injectEnvironmentToHooks(environment, chunkMetadataMap, p),
)
const rolldownOptions: RolldownOptions = {
preserveEntrySignatures: ssr
? 'allow-extension'
: libOptions
? 'strict'
: false,View on GitHub (pinned to b4d66fee14)