evanw/esbuild · critical
Invalid target
Error message
Invalid target
What it means
validateFeatures (pkg/api/api_impl.go:350) panics when BuildOptions.Target is not DefaultTarget(0) nor one of ESNext/ES5/ES2015..ES2026. The target is translated into a compat.Semver constraint used to disable unsupported JS/CSS features; an unknown target cannot be mapped to a feature set, so esbuild aborts. Reached from validateBuildOptions via validateFeatures before engines are processed.
Solutions
- Use DefaultTarget (let esbuild choose) or one of the declared ES* constants that your esbuild version supports; ESNext avoids feature-gating entirely.
- If loading target from a string, map "es2022" etc. to constants at load and reject unknown strings with a clear error.
- Bounds-check decoded integers against 0..14 (the enum length at this version) before casting.
- Upgrade esbuild (and rebuild bridges) to a version that supports the target you need.
Example fix
// before
opts := api.BuildOptions{Target: api.Target(20)}
// after
opts := api.BuildOptions{Target: api.DefaultTarget} Defensive patterns
Strategy: validation
Validate before calling
func checkTarget(t api.Target) error {
switch t {
case api.DefaultTarget, api.ESNext, api.ES5,
api.ES2015, api.ES2016, api.ES2017, api.ES2018, api.ES2019,
api.ES2020, api.ES2021, api.ES2022, api.ES2023, api.ES2024,
api.ES2025, api.ES2026:
return nil
}
return fmt.Errorf("invalid target %d", uint8(t))
} Type guard
func isValidTarget(t api.Target) bool {
switch t {
case api.DefaultTarget, api.ESNext, api.ES5,
api.ES2015, api.ES2016, api.ES2017, api.ES2018, api.ES2019,
api.ES2020, api.ES2021, api.ES2022, api.ES2023, api.ES2024,
api.ES2025, api.ES2026:
return true
}
return false
} Prevention
- Use DefaultTarget unless you need to gate features; ESNext disables feature-gating entirely.
- When parsing a target string from user config, reject unknown values explicitly instead of guessing an ordinal.
- After an esbuild upgrade that adds a new ES20xx constant, regenerate any bridge and widen your validation.
- Bounds-check integers to the current enum length before casting.
When it happens
Trigger: Passing Target as a raw integer outside the declared enum, deserializing it from a numeric config, or referencing a constant that does not exist in this esbuild version (e.g. ES2027 against an older binary). The panic fires during options validation, before any file is scanned.
Common situations: Running against an older esbuild than your config targets (new ES20xx constants are added over time), version drift between the JS API and the Go core after re-vendoring, or a typo such as `Target: api.ES2020Stable`.
Related errors
AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09).
Data as JSON: /api/errors/c7304a3391daf108.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/api/api_impl.go:350
case ES2019:
constraints[compat.ES] = compat.Semver{Parts: []int{2019}}
case ES2020:
constraints[compat.ES] = compat.Semver{Parts: []int{2020}}
case ES2021:
constraints[compat.ES] = compat.Semver{Parts: []int{2021}}
case ES2022:
constraints[compat.ES] = compat.Semver{Parts: []int{2022}}
case ES2023:
constraints[compat.ES] = compat.Semver{Parts: []int{2023}}
case ES2024:
constraints[compat.ES] = compat.Semver{Parts: []int{2024}}
case ES2025:
constraints[compat.ES] = compat.Semver{Parts: []int{2025}}
case ES2026:
constraints[compat.ES] = compat.Semver{Parts: []int{2026}}
case ESNext, DefaultTarget:
default:
panic("Invalid target")
}
for _, engine := range engines {
if match := versionRegex.FindStringSubmatch(engine.Version); match != nil {
if major, err := strconv.Atoi(match[1]); err == nil {
parts := []int{major}
if minor, err := strconv.Atoi(match[2]); err == nil {
parts = append(parts, minor)
if patch, err := strconv.Atoi(match[3]); err == nil {
parts = append(parts, patch)
}
}
name := convertEngineName(engine.Name)
new := compat.Semver{
Parts: parts,
PreRelease: match[4],
}
if old, ok := constraints[name]; ok && compat.CompareSemver(old, new) < 0 {View on GitHub (pinned to f6058f8364)