evanw/esbuild · error · LexerPanic
Unexpected "..."
Error message
Unexpected "..."
What it means
In a parenthesized expression that esbuild concluded is not an arrow function, a spread '...' was present (spreadRange non-empty). Spread is only valid in arrow arguments, calls, or array literals, so as a bare parenthesized element it is illegal.
Source
Thrown at internal/js_parser/js_parser.go:3350
}
// Are these arguments for a call to a function named "async"?
if isAsync {
p.logExprErrors(&errors)
async := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{
Ref: p.storeNameInRef(js_lexer.MaybeSubstring{String: "async"})}}
return js_ast.Expr{Loc: loc, Data: &js_ast.ECall{
Target: async,
Args: items,
}}
}
// Is this a chain of expressions and comma operators?
if len(items) > 0 {
p.logExprErrors(&errors)
if spreadRange.Len > 0 {
p.log.AddError(&p.tracker, spreadRange, "Unexpected \"...\"")
panic(js_lexer.LexerPanic{})
}
value := js_ast.JoinAllWithComma(items)
p.markExprAsParenthesized(value, loc, isAsync)
return value
}
// Indicate that we expected an arrow function
p.lexer.Expected(js_lexer.TEqualsGreaterThan)
return js_ast.Expr{}
}
type invalidLog struct {
invalidTokens []logger.Range
syntaxFeatures []syntaxFeature
}
type syntaxFeature struct {
feature compat.JSFeatureView on GitHub (pinned to f6058f8364)
Solutions
- Add '=> body' to turn it into an arrow function.
- Remove the '...' if spread was not intended as a parameter.
- Move the spread into a call/array context where it is legal.
Example fix
// before const f = (...a) // after const f = (...a) => a
Defensive patterns
Strategy: validation
Validate before calling
import "github.com/evanw/esbuild/pkg/api"
res := api.Transform(src, api.TransformOptions{Loader: api.LoaderJS})
for _, m := range res.Errors {
if strings.Contains(m.Text, "Unexpected \"...\"") {
// spread used outside an arrow/call/array context
}
} Prevention
- Ensure every '(...args)' parameter list is followed by '=> body'.
- Lint with eslint/tsc to catch spread outside legal contexts.
- Review refactors that removed an arrow body.
When it happens
Trigger: '(...args)' or '(...a)' used as a standalone parenthesized expression without a following '=>'.
Common situations: Forgot the '=>'; copy-pasting a function signature; partial refactor that dropped the arrow body.
Related errors
- Unexpected newline before "=>"
- Invalid binding pattern
- Unexpected ":"
- For loop initializers cannot start with "async of"
- Expected identifier after %q in namespaced JSX name
AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09).
Data as JSON: /api/errors/dab8326e62380fd7.
Report an issue: GitHub.