{"record":{"id":"ef4664a6cfec281d","repo":"evanw/esbuild","slug":"for-loop-initializers-cannot-start-with-async-of","errorCode":null,"errorMessage":"For loop initializers cannot start with \"async of\"","messagePattern":"For loop initializers cannot start with \"async of\"","errorType":"panic","errorClass":"LexerPanic","httpStatus":null,"severity":"error","filePath":"internal/js_parser/js_parser.go","lineNumber":3031,"sourceCode":"\t\t\t\t\tneedsAsyncLoc: asyncRange.Loc,\n\t\t\t\t})}\n\t\t\t}\n\n\t\t// \"async x => {}\"\n\t\tcase js_lexer.TIdentifier:\n\t\t\tif level <= js_ast.LAssign {\n\t\t\t\tisArrowFn := true\n\t\t\t\tif (flags&exprFlagForLoopInit) != 0 && p.lexer.Identifier.String == \"of\" {\n\t\t\t\t\t// See https://github.com/tc39/ecma262/issues/2034 for details\n\n\t\t\t\t\t// \"for (async of\" is only an arrow function if the next token is \"=>\"\n\t\t\t\t\tisArrowFn = p.checkForArrowAfterTheCurrentToken()\n\n\t\t\t\t\t// Do not allow \"for (async of []) ;\" but do allow \"for await (async of []) ;\"\n\t\t\t\t\tif !isArrowFn && (flags&exprFlagForAwaitLoopInit) == 0 && p.lexer.Raw() == \"of\" {\n\t\t\t\t\t\tr := logger.Range{Loc: asyncRange.Loc, Len: p.lexer.Range().End() - asyncRange.Loc.Start}\n\t\t\t\t\t\tp.log.AddError(&p.tracker, r, \"For loop initializers cannot start with \\\"async of\\\"\")\n\t\t\t\t\t\tpanic(js_lexer.LexerPanic{})\n\t\t\t\t\t}\n\t\t\t\t} else if p.options.ts.Parse && p.lexer.Token == js_lexer.TIdentifier {\n\t\t\t\t\t// Make sure we can parse the following TypeScript code:\n\t\t\t\t\t//\n\t\t\t\t\t//   export function open(async?: boolean): void {\n\t\t\t\t\t//     console.log(async as boolean)\n\t\t\t\t\t//   }\n\t\t\t\t\t//\n\t\t\t\t\t// TypeScript solves this by using a two-token lookahead to check for\n\t\t\t\t\t// \"=>\" after an identifier after the \"async\". This is done in\n\t\t\t\t\t// \"isUnParenthesizedAsyncArrowFunctionWorker\" which was introduced\n\t\t\t\t\t// here: https://github.com/microsoft/TypeScript/pull/8444\n\t\t\t\t\tisArrowFn = p.checkForArrowAfterTheCurrentToken()\n\t\t\t\t}\n\n\t\t\t\tif isArrowFn {\n\t\t\t\t\tp.markAsyncFn(asyncRange, false)\n\t\t\t\t\tref := p.storeNameInRef(p.lexer.Identifier)","sourceCodeStart":3013,"sourceCodeEnd":3049,"githubUrl":"https://github.com/evanw/esbuild/blob/f6058f8364fe7ab91ca57a83e02577ed74c9cae4/internal/js_parser/js_parser.go#L3013-L3049","documentation":"Per tc39/ecma262#2034, 'for (async of ...)' is ambiguous with an async arrow function and is explicitly disallowed as a for-of initializer unless it is 'for await'. esbuild detects the token sequence 'async' then 'of' in a for-loop initializer and, when it is neither an arrow nor a for-await loop, errors out.","triggerScenarios":"Writing 'for (async of items) {}' (loop variable literally named 'async' in a for-of) without 'await'.","commonSituations":"Naming a loop binding 'async'; code generators that emit 'for (async of ...)'; confusion between async iteration and an 'async' variable name.","solutions":["Rename the loop variable away from 'async' (e.g. 'for (const x of items) {}').","If async iteration was intended, use 'for await (const x of items) {}'.","Use a different loop construct (for-index, forEach)."],"exampleFix":"// before\nfor (async of items) {}\n// after\nfor (const item of items) {}","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, `cannot start with \"async of\"`) {\n    // m.Location marks the 'async' token; ask user to rename the binding\n  }\n}","typeGuard":"// Flag a for-of loop whose binding is the bare identifier 'async'.\nvar reForAsyncOf = regexp.MustCompile(`(?m)\\\\sfor\\\\s*\\\\(\\\\s*async\\\\s+of\\\\b`)\nfunc hasForAsyncOf(src string) bool { return reForAsyncOf.MatchString(src) }","tryCatchPattern":null,"preventionTips":["Avoid 'async' as a variable/loop-binding name.","Lint with eslint (no-unused-labels / identifier rules) to flag keyword-like names.","For async iteration use 'for await ... of'."],"tags":["syntax-error","parser","async","for-loop"],"backgroundTag":null,"analyzedSha":"f6058f8364fe7ab91ca57a83e02577ed74c9cae4","analyzedAt":"2026-08-09T18:37:22.223Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}