{"record":{"id":"2c4a25b3b37ef9d3","repo":"microsoft/TypeScript","slug":"generator-is-already-executing","errorCode":null,"errorMessage":"Generator is already executing.","messagePattern":"Generator is already executing\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/compiler/factory/emitHelpers.ts","lineNumber":1125,"sourceCode":"//                        evaluates any intervening finally blocks between the current\r\n//                        label and the nearest catch block or function boundary. If\r\n//                        uncaught, the exception is thrown to the caller.\r\n//  7: endfinally       - Ends a finally block, resuming the last instruction prior to\r\n//                        entering a finally block.\r\n//\r\n// For examples of how these are used, see the comments in ./transformers/generators.ts\r\nconst generatorHelper: UnscopedEmitHelper = {\r\n    name: \"typescript:generator\",\r\n    importName: \"__generator\",\r\n    scoped: false,\r\n    priority: 6,\r\n    text: `\r\n            var __generator = (this && this.__generator) || function (thisArg, body) {\r\n                var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\r\n                return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n                function verb(n) { return function (v) { return step([n, v]); }; }\r\n                function step(op) {\r\n                    if (f) throw new TypeError(\"Generator is already executing.\");\r\n                    while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n                        if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n                        if (y = 0, t) op = [op[0] & 2, t.value];\r\n                        switch (op[0]) {\r\n                            case 0: case 1: t = op; break;\r\n                            case 4: _.label++; return { value: op[1], done: false };\r\n                            case 5: _.label++; y = op[1]; op = [0]; continue;\r\n                            case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n                            default:\r\n                                if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n                                if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n                                if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n                                if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n                                if (t[2]) _.ops.pop();\r\n                                _.trys.pop(); continue;\r\n                        }\r\n                        op = body.call(thisArg, _);\r\n                    } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r","sourceCodeStart":1107,"sourceCodeEnd":1143,"githubUrl":"https://github.com/microsoft/TypeScript/blob/b465fdbfe175304d9b977da137b2c178ae1091d3/src/compiler/factory/emitHelpers.ts#L1107-L1143","documentation":"`__generator` downlevels ES6 generators into a state machine and guards against synchronous re-entry: a flag `f` is set while the body is executing, and re-entering `step` while `f` is set throws \"Generator is already executing.\" — matching native generator semantics where synchronous re-entry is illegal.","triggerScenarios":"Code inside the generator body synchronously calls .next(), .throw(), or .return() on the same generator instance before the current step has returned.","commonSituations":"A generator that recursively drives itself; a callback passed out of the generator that re-advances it within the same tick; a thunk that synchronously re-invokes the generator.","solutions":["Do not synchronously re-enter the generator; defer advancement via setTimeout/queueMicrotask or yield first.","Restructure so the generator yields before any code that could re-advance it runs.","Test generators for re-entrancy when porting callback-style code to generators."],"exampleFix":"// before\nfunction* g() {\n  self.next();   // synchronous re-entry -> \"Generator is already executing.\"\n  yield 1;\n}\nconst self = g(); self.next();\n\n// after\nfunction* g() {\n  queueMicrotask(() => self.next());  // defer\n  yield 1;\n}\nconst self = g(); self.next();","handlingStrategy":"validation","validationCode":"// Re-entrancy guard for self-driving generators.\nlet executing = false;\nfunction safeNext(g: Generator, v?: unknown) {\n  if (executing) throw new TypeError(\"Generator is already executing.\");\n  executing = true;\n  try { return g.next(v); } finally { executing = false; }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call .next/.throw/.return on a generator from within its own body synchronously.","Defer self-advancement with queueMicrotask/setTimeout or yield first.","When porting callback code to generators, audit for synchronous re-entry."],"tags":["generators","runtime","emit-helpers"],"backgroundTag":null,"analyzedSha":"b465fdbfe175304d9b977da137b2c178ae1091d3","analyzedAt":"2026-08-12T05:38:42.698Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}