vitejs/vite · error · Error

failed to resolve rolldownOptions.input value

Error message

failed to resolve rolldownOptions.input value: ${JSON.stringify(p)}.

What it means

Thrown during dependency scanning when `rolldownOptions.input` (or `build.rolldownOptions.input`, or `environment.config.input`) is set, and one of its values cannot be resolved to a file id by Vite's plugin container. `resolvePath` returns undefined and scan.ts:231 throws, naming the offending input value via JSON.stringify.

Solutions

  1. Verify the input path exists and is resolvable from the project root; print it with `console.log(path.resolve(input))`.
  2. If it is a bare specifier or virtual id, add a plugin that resolves it during the scan (handle `isEntry: true, scan: true`).
  3. Use `optimizeDeps.entries` with glob patterns for HTML/JS files instead of a single missing path.
  4. Fix or remove aliases that are misconfigured for the scan phase.
  5. Ensure the file is present on disk (un-ignore, restore from git, reinstall workspace).

Example fix

// before
export default defineConfig({
  build: { rollupOptions: { input: './src/main.html' } }, // typo, real file is index.html
})

// after
export default defineConfig({
  build: { rollupOptions: { input: './index.html' } },
})
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs'
import path from 'node:path'

function resolveInput(input: unknown, root: string): string[] {
  const list: string[] = typeof input === 'string' ? [input]
    : Array.isArray(input) ? input
    : isObject(input) ? Object.values(input)
    : []
  for (const p of list) {
    const abs = path.isAbsolute(p) ? p : path.resolve(root, p)
    if (!fs.existsSync(abs)) throw new Error(`build.rolldownOptions.input '${p}' does not resolve to an existing file`)
  }
  return list
}
// call resolveInput(config.build.rolldownOptions.input, config.root) before server start

Type guard

function isInputValue(v: unknown): v is string | string[] | Record<string, string> {
  return typeof v === 'string' || Array.isArray(v) || (typeof v === 'object' && v !== null && !Array.isArray(v))
}

Try / catch

try {
  await server.listen()
} catch (e) {
  if (e instanceof Error && /failed to resolve rolldownOptions\.input value:/.test(e.message)) {
    const val = e.message.match(/value: (.*)\./)?.[1]
    console.error(`Input ${val} could not be resolved; check path/alias and retry.`)
  }
  throw e
}

Prevention

When it happens

Trigger: Config sets `build.rollupOptions.input` / `optimizeDeps.entries` / environment `input` to a path or bare specifier that `pluginContainer.resolveId(p, undefined, { isEntry: true, scan: true })` cannot resolve. Triggered at server/build startup during `computeEntries`.

Common situations: Typo in the input path. Path relative to wrong root (input must be resolvable from project root, or absolute). Input points to a virtual module not handled by a plugin during scan. File was deleted or gitignored. Monorepo where the input lives in another package not symlinked. Conditional alias not active during scan.

Related errors


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

Appendix: source

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

async function computeEntries(environment: ScanEnvironment) {
  let entries: string[] = []

  const explicitEntryPatterns = environment.config.optimizeDeps.entries
  const input =
    environment.config.input ?? environment.config.build.rolldownOptions.input

  if (explicitEntryPatterns) {
    entries = await globEntries(explicitEntryPatterns, environment)
  } else if (input) {
    const resolvePath = async (p: string) => {
      const id = (
        await environment.pluginContainer.resolveId(p, undefined, {
          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)
  }

View on GitHub (pinned to b4d66fee14)