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

  1. Point rolldownOptions.input at the JS/TS entry that imports the CSS, not at the .css file directly.
  2. If you truly need a standalone CSS bundle, leave cssCodeSplit at its default (true) and import the stylesheet from JS so Vite extracts it.
  3. 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

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


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)