{"record":{"id":"615f32fa1e9f7274","repo":"evanw/esbuild","slug":"unexpected-newline-after-async","errorCode":null,"errorMessage":"Unexpected newline after \"async\"","messagePattern":"Unexpected newline after \"async\"","errorType":"panic","errorClass":"LexerPanic","httpStatus":null,"severity":"error","filePath":"internal/js_parser/js_parser.go","lineNumber":7169,"sourceCode":"\t\t\t}\n\n\t\t\tif p.lexer.IsContextualKeyword(\"as\") {\n\t\t\t\t// \"export as namespace ns;\"\n\t\t\t\tp.lexer.Next()\n\t\t\t\tp.lexer.ExpectContextualKeyword(\"namespace\")\n\t\t\t\tp.lexer.Expect(js_lexer.TIdentifier)\n\t\t\t\tp.lexer.ExpectOrInsertSemicolon()\n\t\t\t\treturn js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}\n\t\t\t}\n\n\t\t\tif p.lexer.IsContextualKeyword(\"async\") {\n\t\t\t\t// \"export async function foo() {}\"\n\t\t\t\tasyncRange := p.lexer.Range()\n\t\t\t\tp.lexer.Next()\n\t\t\t\tif p.lexer.HasNewlineBefore {\n\t\t\t\t\tp.log.AddError(&p.tracker, logger.Range{Loc: logger.Loc{Start: asyncRange.End()}},\n\t\t\t\t\t\t\"Unexpected newline after \\\"async\\\"\")\n\t\t\t\t\tpanic(js_lexer.LexerPanic{})\n\t\t\t\t}\n\t\t\t\tp.lexer.Expect(js_lexer.TFunction)\n\t\t\t\topts.isExport = true\n\t\t\t\treturn p.parseFnStmt(loc, opts, true /* isAsync */, asyncRange)\n\t\t\t}\n\n\t\t\tif p.options.ts.Parse {\n\t\t\t\tswitch p.lexer.Identifier.String {\n\t\t\t\tcase \"type\":\n\t\t\t\t\t// \"export type foo = ...\"\n\t\t\t\t\ttypeRange := p.lexer.Range()\n\t\t\t\t\tp.lexer.Next()\n\t\t\t\t\tif p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace && p.lexer.Token != js_lexer.TAsterisk {\n\t\t\t\t\t\tp.log.AddError(&p.tracker, logger.Range{Loc: logger.Loc{Start: typeRange.End()}},\n\t\t\t\t\t\t\t\"Unexpected newline after \\\"type\\\"\")\n\t\t\t\t\t\tpanic(js_lexer.LexerPanic{})\n\t\t\t\t\t}\n\t\t\t\t\tp.skipTypeScriptTypeStmt(parseStmtOpts{isModuleScope: opts.isModuleScope, isExport: true})","sourceCodeStart":7151,"sourceCodeEnd":7187,"githubUrl":"https://github.com/evanw/esbuild/blob/f6058f8364fe7ab91ca57a83e02577ed74c9cae4/internal/js_parser/js_parser.go#L7151-L7187","documentation":"In 'export async function ...', automatic semicolon insertion is not permitted between 'async' and 'function'. esbuild checks HasNewlineBefore after consuming 'async' (js_parser.go:7166) and, if a line break precedes 'function', errors.","triggerScenarios":"'export async\\nfunction foo() {}' — a line break between 'async' and 'function' in an exported async function declaration.","commonSituations":"A formatter/prettier line-wrapping the keyword onto its own line; manual edits splitting the declaration.","solutions":["Keep 'async function' together with no line break between them.","Reformat so 'export async function' sits on one line (or wrap elsewhere)."],"exampleFix":"// before\nexport async\nfunction foo() {}\n// after\nexport async function foo() {}","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, `Unexpected newline after \"async\"`) {\n    // a line break sits between 'async' and 'function' in an export\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep 'async function' on one line in export declarations.","Run tsc/eslint to catch ASI-incompatible line breaks.","Configure prettier not to break between 'async' and 'function'."],"tags":["syntax-error","parser","async","export","newline"],"backgroundTag":null,"analyzedSha":"f6058f8364fe7ab91ca57a83e02577ed74c9cae4","analyzedAt":"2026-08-09T18:37:22.223Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}