{"record":{"id":"db23244a47572b91","repo":"karatelabs/karate","slug":"generator-is-already-running","errorCode":null,"errorMessage":"Generator is already running","messagePattern":"Generator is already running","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/GeneratorActivation.java","lineNumber":151,"sourceCode":"    }\n\n    /** {@code return(v)} / {@code throw(e)} on a NOT_STARTED or DONE generator\n     *  runs no body code — just retire it. */\n    void retire() {\n        state.set(State.DONE);\n    }\n\n    /**\n     * One driver step: deposit the resume input, hand the coroutine the lock,\n     * park until it yields / returns / throws, and return the outcome. Caller\n     * (JsGenerator) has already done brand/state shortcuts; this method owns\n     * the RUNNING transition.\n     */\n    StepOutcome step(ResumeKind kind, Object value) {\n        anyGenerators = true;\n        State s = state.get();\n        if (s == State.RUNNING) {\n            throw JsErrorException.typeError(\"Generator is already running\");\n        }\n        if (s == State.DONE) {\n            // raced with a concurrent completion — treat as done\n            return new StepOutcome(OutcomeKind.RETURNED, Terms.UNDEFINED);\n        }\n        if (!state.compareAndSet(s, State.RUNNING)) {\n            // a concurrent host caller won the step; spec answer is the same\n            // \"already running\" TypeError\n            throw JsErrorException.typeError(\"Generator is already running\");\n        }\n        AtomicReference<StepOutcome> cell = new AtomicReference<>();\n        stepCell = cell;\n        resumeKind = kind;\n        resumeValue = value;\n        driver = Thread.currentThread();\n        // register-only-if-open: a RUNNING step is scope-owned, cancellable\n        // work; a closed scope must not accept it\n        AsyncScope scope = engine.currentScope();","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/GeneratorActivation.java#L133-L169","documentation":"The generator machinery (GeneratorActivation.step) throws this TypeError when a generator whose state is already RUNNING is asked to take another step. This corresponds to the ECMAScript rule that you cannot call next()/return()/throw() on a generator from inside its own execution (e.g. via its iterator indirectly). The state check is an AtomicReference compare so concurrent host callers also funnel here (line 151 is the direct state==RUNNING check).","triggerScenarios":"Calling gen.next() (directly or through spread/for-of) from within the generator's own body or from a callback invoked while the generator is executing; re-entrant resume through shared state; two host threads stepping the same generator activation.","commonSituations":"Generator yields into a callback that itself consumes the same iterator; recursive iteration over a generator that feeds itself; multithreaded host code sharing a generator instance across threads.","solutions":["Do not consume the generator from within its own execution — collect results first, then iterate","If re-entrancy is needed, create a second independent generator instance","Buffer yielded values into an array/queue and iterate the buffer inside the generator body","In host code, synchronize or confine each generator to a single thread"],"exampleFix":"// before\nfunction* g() { for (const v of g()) yield v; } // self-consumption\n// after\nfunction* g(src) { for (const v of src) yield v * 2; }\nconst it = g([1,2,3]);","handlingStrategy":"try-catch","validationCode":"// ensure you never iterate a generator inside its own body:\n// pass the source collection in as a parameter instead of self-referencing","typeGuard":"function canStep(gen) { return gen && !gen.__running; }","tryCatchPattern":"try { var r = gen.next(); } catch (e) { if (String(e).includes('Generator is already running')) { /* restructure: don't re-enter */ } else { throw e; } }","preventionTips":["Never consume an iterator from inside its own generator body","Buffer results before re-iterating","One consumer per generator instance"],"tags":["javascript","generator","typeerror","reentrancy"],"backgroundTag":"invalid-state-transition","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}