{"record":{"id":"95d499134a31a507","repo":"evanw/esbuild","slug":"expected-identifier-but-found-q","errorCode":null,"errorMessage":"Expected identifier but found %q","messagePattern":"Expected identifier but found %q","errorType":"panic","errorClass":"LexerPanic","httpStatus":null,"severity":"error","filePath":"internal/js_parser/js_parser.go","lineNumber":5989,"sourceCode":"\t\t\tisSingleLine = false\n\t\t}\n\t\tp.lexer.Next()\n\t\tif p.lexer.HasNewlineBefore {\n\t\t\tisSingleLine = false\n\t\t}\n\t}\n\n\tif p.lexer.HasNewlineBefore {\n\t\tisSingleLine = false\n\t}\n\tp.lexer.Expect(js_lexer.TCloseBrace)\n\n\t// Throw an error here if we found a keyword earlier and this isn't an\n\t// \"export from\" statement after all\n\tif firstNonIdentifierLoc.Start != 0 && !p.lexer.IsContextualKeyword(\"from\") {\n\t\tr := js_lexer.RangeOfIdentifier(p.source, firstNonIdentifierLoc)\n\t\tp.log.AddError(&p.tracker, r, fmt.Sprintf(\"Expected identifier but found %q\", p.source.TextForRange(r)))\n\t\tpanic(js_lexer.LexerPanic{})\n\t}\n\n\treturn items, isSingleLine\n}\n\ntype parseBindingOpts struct {\n\tisUsingStmt bool\n}\n\nfunc (p *parser) parseBinding(opts parseBindingOpts) js_ast.Binding {\n\tloc := p.lexer.Loc()\n\n\tswitch p.lexer.Token {\n\tcase js_lexer.TIdentifier:\n\t\tname := p.lexer.Identifier\n\n\t\t// Forbid invalid identifiers\n\t\tif (p.fnOrArrowDataParse.await != allowIdent && name.String == \"await\") ||","sourceCodeStart":5971,"sourceCodeEnd":6007,"githubUrl":"https://github.com/evanw/esbuild/blob/f6058f8364fe7ab91ca57a83e02577ed74c9cae4/internal/js_parser/js_parser.go#L5971-L6007","documentation":"In the named import/export clause parser, esbuild recorded a non-identifier (reserved keyword) where a binding name was expected, and the statement did not turn out to be an 'export ... from' re-export. It then reports 'Expected identifier but found <token>'.","triggerScenarios":"import { default } from 'mod' or export { class } — using a reserved word as a bare specifier name without aliasing, or a stray keyword in the clause list.","commonSituations":"Using reserved words as import/export names without 'as'; typos; generated code emitting keywords as names.","solutions":["Alias reserved words: import { default as d } from 'mod', or use default-import syntax import d from 'mod'.","Correct the keyword to a real identifier.","Re-check generated specifier lists for stray keywords."],"exampleFix":"// before\nimport { default } from 'mod'\n// after\nimport d from 'mod'","handlingStrategy":"validation","validationCode":"import \"github.com/evanw/esbuild/pkg/api\"\nres := api.Transform(src, api.TransformOptions{Loader: api.LoaderJS})\nfor _, m := range res.Errors {\n  if strings.Contains(m.Text, \"Expected identifier but found\") {\n    // a reserved word was used as an import/export binding name\n  }\n}","typeGuard":"// Flag reserved words used as bare names in import/export clauses.\nvar reserved = map[string]bool{\"default\": true, \"class\": true, \"function\": true, \"return\": true, \"var\": true, \"let\": true, \"const\": true}\nvar reClauseName = regexp.MustCompile(`(?:import|export)\\\\s*\\\\{([^}]*)\\\\}`)\nfunc importExportUsesReservedWord(src string) bool {\n  for _, m := range reClauseName.FindAllStringSubmatch(src, -1) {\n    for _, part := range strings.Split(m[1], \",\") {\n      name := strings.TrimSpace(strings.Fields(part)[0])\n      if reserved[name] { return true }\n    }\n  }\n  return false\n}","tryCatchPattern":null,"preventionTips":["Alias reserved words in clauses: import { default as d }.","Use default-import syntax (import d from 'm') instead of { default }.","Lint import/export specifier lists with eslint-plugin-import."],"tags":["syntax-error","parser","import-export"],"backgroundTag":null,"analyzedSha":"f6058f8364fe7ab91ca57a83e02577ed74c9cae4","analyzedAt":"2026-08-09T18:37:22.223Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}