microsoft/TypeScript · error · TypeError
Generator is already executing.
Error message
Generator is already executing.
What it means
`__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.
Source
Thrown at src/compiler/factory/emitHelpers.ts:1125
// evaluates any intervening finally blocks between the current
// label and the nearest catch block or function boundary. If
// uncaught, the exception is thrown to the caller.
// 7: endfinally - Ends a finally block, resuming the last instruction prior to
// entering a finally block.
//
// For examples of how these are used, see the comments in ./transformers/generators.ts
const generatorHelper: UnscopedEmitHelper = {
name: "typescript:generator",
importName: "__generator",
scoped: false,
priority: 6,
text: `
var __generator = (this && this.__generator) || function (thisArg, body) {
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);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
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;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
View on GitHub (pinned to b465fdbfe1)
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.
Example fix
// before
function* g() {
self.next(); // synchronous re-entry -> "Generator is already executing."
yield 1;
}
const self = g(); self.next();
// after
function* g() {
queueMicrotask(() => self.next()); // defer
yield 1;
}
const self = g(); self.next(); Defensive patterns
Strategy: validation
Validate before calling
// Re-entrancy guard for self-driving generators.
let executing = false;
function safeNext(g: Generator, v?: unknown) {
if (executing) throw new TypeError("Generator is already executing.");
executing = true;
try { return g.next(v); } finally { executing = false; }
} Prevention
- 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.
When it happens
Trigger: Code inside the generator body synchronously calls .next(), .throw(), or .return() on the same generator instance before the current step has returned.
Common situations: 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.
Related errors
- Function expected
- Cannot add initializers after decoration has completed
- Object expected
- Symbol.asyncIterator is not defined.
- Class extends value ${String(b)} is not a constructor or nul
AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12).
Data as JSON: /api/errors/2c4a25b3b37ef9d3.
Report an issue: GitHub.