vitejs/vite · error · Error

invalid rolldownOptions.input value.

Error message

invalid rolldownOptions.input value.

What it means

Thrown by `computeEntries` when `rolldownOptions.input` is set but is neither a string, an array, nor a plain object — the three shapes the resolver knows how to iterate. scan.ts:244 throws unconditionally for any other type (e.g. number, function, null after a truthy check passes).

Solutions

  1. Set `build.rolldownOptions.input` to a string, an array of strings, or a record `{ name: path }`.
  2. Resolve dynamic input to a concrete array before returning config.
  3. If you need code-splitting entry objects, use the `{ [name]: path }` form.
  4. Type-check the config (`vite config` / `tsc`) to catch shape errors before run.

Example fix

// before
export default defineConfig({
  build: { rollupOptions: { input: () => findEntries() } }, // function unsupported
})

// after
const entries = await findEntries()
export default defineConfig({
  build: { rollupOptions: { input: entries } }, // string[]
})
Defensive patterns

Strategy: type-guard

Validate before calling

function assertInputShape(input: unknown) {
  if (typeof input !== 'string' && !Array.isArray(input) && (typeof input !== 'object' || input === null || Array.isArray(input) || input instanceof Map || typeof input === 'function')) {
    throw new TypeError('rolldownOptions.input must be string, string[], or Record<string,string>')
  }
}

Type guard

function isValidInput(v: unknown): v is string | string[] | Record<string, string> {
  if (typeof v === 'string') return true
  if (Array.isArray(v)) return v.every((x) => typeof x === 'string')
  if (v && typeof v === 'object' && !(v instanceof Map) && typeof v !== 'function') {
    return Object.values(v).every((x) => typeof x === 'string')
  }
  return false
}

Try / catch

try {
  await server.listen()
} catch (e) {
  if (e instanceof Error && e.message === 'invalid rolldownOptions.input value.') {
    console.error('rolldownOptions.input must be string, string[], or Record<string,string>; got', config.build.rolldownOptions.input)
  }
  throw e
}

Prevention

When it happens

Trigger: `build.rolldownOptions.input` (or `config.input`) is assigned a value of an unsupported type. The isObject check at scan.ts:241 passes for arrays-as-objects only via Array.isArray first; any other non-plain object (Map, function, class instance) falls through to line 244.

Common situations: Programmatic config that computes input dynamically and yields an unexpected type. Passing a Rollup-style `{ main: () => ... }` or a function. Misconfigured plugin that mutates input. Copy-paste from Rollup examples using unsupported shapes.

Related errors


AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11). Data as JSON: /api/errors/946847f8dfa3008f. Report an issue: GitHub.

Appendix: source

Thrown at packages/vite/src/node/optimizer/scan.ts:244

          isEntry: true,
          scan: true,
        })
      )?.id
      if (id === undefined) {
        throw new Error(
          `failed to resolve rolldownOptions.input value: ${JSON.stringify(p)}.`,
        )
      }
      return id
    }
    if (typeof input === 'string') {
      entries = [await resolvePath(input)]
    } else if (Array.isArray(input)) {
      entries = await Promise.all(input.map(resolvePath))
    } else if (isObject(input)) {
      entries = await Promise.all(Object.values(input).map(resolvePath))
    } else {
      throw new Error('invalid rolldownOptions.input value.')
    }
  } else {
    entries = await globEntries('**/*.html', environment)
  }

  // Non-supported entry file types and virtual files should not be scanned for
  // dependencies.
  entries = entries.filter(
    (entry) =>
      isScannable(entry, environment.config.optimizeDeps.extensions) &&
      fs.existsSync(entry),
  )

  return entries
}

async function prepareRolldownScanner(
  environment: ScanEnvironment,

View on GitHub (pinned to b4d66fee14)