evanw/esbuild · error · LexerPanic
Unexpected ":"
Error message
Unexpected ":"
What it means
After parsing a parenthesized group that turned out NOT to be an arrow function, esbuild still saw a TypeScript-style ':' type annotation (typeColonRange non-empty). Type annotations are only legal on arrow-function parameters, so the ':' is unexpected and parsing fails.
Source
Thrown at internal/js_parser/js_parser.go:3331
needsAsyncLoc: loc,
await: await,
})
arrow.IsAsync = isAsync
arrow.HasRestArg = spreadRange.Len > 0
p.popScope()
return js_ast.Expr{Loc: loc, Data: arrow}
}
}
// If we get here, it's not an arrow function so undo the pushing of the
// scope we did earlier. This needs to flatten any child scopes into the
// parent scope as if the scope was never pushed in the first place.
p.popAndFlattenScope(scopeIndex)
// If this isn't an arrow function, then types aren't allowed
if typeColonRange.Len > 0 {
p.log.AddError(&p.tracker, typeColonRange, "Unexpected \":\"")
panic(js_lexer.LexerPanic{})
}
// 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 \"...\"")View on GitHub (pinned to f6058f8364)
Solutions
- Add the '=> body' to make it an arrow function.
- If the file is TypeScript, build with the ts/tsx loader (esbuild default for .ts/.tsx).
- Remove the ':' annotation for plain JavaScript.
Example fix
// before const f = (x: number) // after const f = (x: number) => x
Defensive patterns
Strategy: validation
Validate before calling
import "github.com/evanw/esbuild/pkg/api"
opts := api.TransformOptions{Loader: api.LoaderTS} // correct loader for TS annotations
res := api.Transform(src, opts)
for _, m := range res.Errors {
if strings.Contains(m.Text, "Unexpected \":\"") {
// annotation parsed outside an arrow; fix the source or loader
}
} Prevention
- Match the file extension to the right loader (.ts/.tsx -> TS, .js -> JS).
- Run tsc to ensure arrow functions have a body after their typed params.
- When porting TS to JS, strip type annotations with a tool, not by hand.
When it happens
Trigger: '(x: number)' used as a standalone parenthesized expression with no '=>', or TS annotations parsed under a non-TS loader.
Common situations: TypeScript type annotation left in a .js file (wrong loader); a parameter list missing its '=> body'; refactoring a signature into an expression.
Related errors
- Unexpected newline before "=>"
- Invalid binding pattern
- Unexpected "..."
- Unexpected newline after "type"
- Unexpected "interface"
AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09).
Data as JSON: /api/errors/3c648d0ba70656ba.
Report an issue: GitHub.