vitejs/vite · error · Error
Unsupported target
Error message
Unsupported target "${entry}" What it means
Thrown by `convertTargets` after ES-year expansion when iterating individual target entries: the entry is not `esnext`, does not match a known browser prefix in `map` (chrome, edge, firefox, ie, ios, node, opera, rhino, safari), or matches a browser `map` marks false (node, hermes, rhino) without further handling, or its version portion is unparseable. css.ts:3652 throws with the entry.
Solutions
- Use only supported browser targets with version: chrome, edge, firefox, ie, ios, opera, safari (e.g. 'chrome110', 'safari16').
- For node/rhino/hermes targets that map=false, ensure the prefix is recognized so they are skipped, or remove them.
- Replace 'deno'/'bun'/'chrome-android' with their closest supported equivalents (e.g. 'chrome' for chromium-based).
- Set `build.target: 'esnext'` or `'baseline-widely-available'` to avoid manual browser targeting.
- Disable Lightning CSS (`css.transformer` default) if you must keep unsupported targets.
Example fix
// before
export default defineConfig({
build: { target: ['deno', 'chrome107'] },
})
// after
export default defineConfig({
build: { target: ['chrome107', 'firefox110', 'safari16'] },
}) Defensive patterns
Strategy: validation
Validate before calling
const BROWSER_MAP = { chrome: true, edge: true, firefox: true, ie: true, ios: true, opera: true, safari: true, node: true, hermes: true, rhino: true }
function assertBrowserTargets(target: string | string[]) {
for (const t of Array.isArray(target) ? target : [target]) {
if (t === 'esnext') continue
const m = /^([a-z]+)([\d.]+)/.exec(t)
if (!m || !(m[1] in BROWSER_MAP)) throw new Error(`Unsupported target '${t}'; use chrome/edge/firefox/ie/ios/opera/safari with a version.`)
}
} Type guard
function isSupportedBrowserTarget(t: string): boolean {
if (t === 'esnext') return true
const m = /^([a-z]+)([\d.]+)/.exec(t)
return !!m && ['chrome', 'edge', 'firefox', 'ie', 'ios', 'opera', 'safari', 'node', 'hermes', 'rhino'].includes(m[1])
} Try / catch
try {
await build()
} catch (e) {
if (e instanceof Error && /Unsupported target/.test(e.message)) {
console.error('build.target has an unsupported browser entry; use chrome/edge/firefox/ie/ios/opera/safari with versions.')
}
throw e
} Prevention
- Use supported browser prefixes (chrome, edge, firefox, ie, ios, opera, safari) with versions for build.target.
- Avoid deno/bun/chrome-android targets under Lightning CSS; map them to supported equivalents.
- Prefer 'baseline-widely-available' or 'esnext' to sidestep manual browser targeting.
When it happens
Trigger: After ES handling, line 3632 loops `entriesWithoutES`; for each entry it slices the alphabetic prefix and looks it up in `map`. If `map[prefix]` is undefined (unknown browser like 'deno', 'bun', 'chrome-android') or the entry's version digits do not parse, line 3652 throws.
Common situations: Setting `build.target: ['deno', 'bun', 'chrome107']`. Using a mobile/Android variant (`chrome-android`, 'safari-ios') not in the map. Typo (`firefo100`). Targets like `node18` (map marks node=false so they are skipped at 3637 only if matched; an unrecognized prefix falls through to 3652).
Related errors
- Unsupported target
- Failed to load PostCSS config
- Name in package.json is required if option…
- When "build.cssCodeSplit: false" is set…
- config must export or return an object.
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/8d6bd11a25bdb9f2.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/plugins/css.ts:3652
const index = entry.search(versionRE)
if (index >= 0) {
const browser = map[entry.slice(0, index)]
if (browser === false) continue // No mapping available
if (browser) {
const [major, minor = 0] = entry
.slice(index)
.split('.')
.map((v) => parseInt(v, 10))
if (!isNaN(major) && !isNaN(minor)) {
const version = (major << 16) | (minor << 8)
if (!targets[browser] || version < targets[browser]!) {
targets[browser] = version
}
continue
}
}
}
throw new Error(`Unsupported target "${entry}"`)
}
convertTargetsCache.set(esbuildTarget, targets)
return targets
}
export function resolveLibCssFilename(
libOptions: LibraryOptions,
root: string,
packageCache?: PackageCache,
): string {
if (typeof libOptions.cssFileName === 'string') {
return `${libOptions.cssFileName}.css`
} else if (typeof libOptions.fileName === 'string') {
return `${libOptions.fileName}.css`
}
const packageJson = findNearestMainPackageData(root, packageCache)?.dataView on GitHub (pinned to b4d66fee14)