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

  1. Add the '=> body' to make it an arrow function.
  2. If the file is TypeScript, build with the ts/tsx loader (esbuild default for .ts/.tsx).
  3. 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

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


AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09). Data as JSON: /api/errors/3c648d0ba70656ba. Report an issue: GitHub.