vitejs/vite · error · Error
Unsupported target
Error message
Unsupported target "${e}" What it means
Thrown by `convertTargets` (the bridge from esbuild-style build targets to Lightning CSS targets) when a target like `esXXXX` has a year not in the supported esMap (currently 2015/2016/2017/2018/2019/2020/2021/2022/2023/2024). css.ts:3628 throws with the offending target string. Only happens when Vite uses Lightning CSS for minification/targeting.
Solutions
- Use a supported ES year: 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, or 2024.
- Upgrade Vite to a version whose esMap includes the year you need.
- Use `'esnext'` (skipped at line 3633) if you do not need a pinned year.
- Switch `css.transformer` off `'lightningcss'` to bypass convertTargets entirely.
- Replace `es<year>` with explicit browser targets (chromeXX, firefoxXX, safariXX, edgeXX).
Example fix
// before
export default defineConfig({
build: { target: 'es2025' }, // not in esMap yet
})
// after
export default defineConfig({
build: { target: 'es2024' },
}) Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED_ES = new Set([2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024])
function assertEsTarget(target: string | string[]) {
for (const t of Array.isArray(target) ? target : [target]) {
const m = /^es(6|\d{4})$/.exec(t)
if (m) {
const year = m[1] === '6' ? 2015 : Number(m[1])
if (!SUPPORTED_ES.has(year)) throw new Error(`Unsupported ES target '${t}'; supported years: ${[...SUPPORTED_ES].join(', ')}`)
}
}
} Type guard
function isSupportedEsTarget(t: string): boolean {
const m = /^es(6|\d{4})$/.exec(t)
if (!m) return false
const year = m[1] === '6' ? 2015 : Number(m[1])
return new Set([2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024]).has(year)
} Try / catch
try {
await build()
} catch (e) {
if (e instanceof Error && /Unsupported target/.test(e.message)) {
console.error('build.target contains an unsupported ES year; use a supported year or esnext.')
}
throw e
} Prevention
- Pin build.target to a supported ES year from Vite's esMap, or use 'esnext'.
- Upgrade Vite when adopting newer ES years (es2025+).
- Unit-test config target values against the supported set in CI.
When it happens
Trigger: `build.target` or `css.lightningcss.targets` includes `es<year>` (matched by `/es(6|\d{4})/`) where the year is not a key in esMap. E.g. `es2025`, `es2014`, `es2018` is fine but a future/unknown year throws. Reached via the `convertTargets` cache-miss path at line 3628.
Common situations: Setting `build.target: 'es2025'` before the bundled Vite supports it. Typo like `es0215`. Copying a target from a newer Vite version into an older one. Lightning CSS enabled (`css.transformer: 'lightningcss'`) with a target Vite's esMap does not yet know.
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/9b6a50f4c6b3edf8.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/plugins/css.ts:3628
const versionRE = /\d/
const convertTargetsCache = new Map<
string | string[],
LightningCSSOptions['targets']
>()
export const convertTargets = (
esbuildTarget: string | string[] | false,
): LightningCSSOptions['targets'] => {
if (!esbuildTarget) return {}
const cached = convertTargetsCache.get(esbuildTarget)
if (cached) return cached
const targets: LightningCSSOptions['targets'] = {}
const entriesWithoutES = arraify(esbuildTarget).flatMap((e) => {
const match = esRE.exec(e)
if (!match) return e
const year = match[1] === '6' ? 2015 : Number(match[1])
if (!esMap[year]) throw new Error(`Unsupported target "${e}"`)
return esMap[year]
})
for (const entry of entriesWithoutES) {
if (entry === 'esnext') continue
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] = versionView on GitHub (pinned to b4d66fee14)