karatelabs/karate · error · JsErrorException

Generator is already running

Error message

Generator is already running

What it means

generator.return(value) was called while the generator's activation is currently executing (running). Per the generator protocol a generator cannot be resumed from within its own frame, so the engine throws a TypeError instead of corrupting the activation stack. This is surfaced by JsGenerator.returnValue when isDone/isStarted checks pass but the activation is marked running.

Solutions

  1. Move the gen.return(...) call outside the generator body, after the driving loop completes.
  2. Use a flag/queue so the inner code signals completion instead of calling return() directly.
  3. If the body should stop, throw or return from inside the body rather than calling gen.return() on itself.
  4. Review with a call-flow check whether any closure invoked by the generator retains the generator reference.

Example fix

// before (inside generator body invoked callback)
onDone: () => gen.return(result)
// after: signal via flag, call return() outside
onDone: () => finished = true;
// ...later, outside the generator frame:
if (finished) gen.return(result);
Defensive patterns

Strategy: try-catch

Validate before calling

// no caller-side pre-check exists for running state; avoid re-entrant gen.return() by design

Try / catch

try { gen.return(v); } catch (e) { if (String(e).indexOf('already running') !== -1) { pendingReturn = v; } else { throw e; } }

Prevention

When it happens

Trigger: Calling gen.return(x) from inside the generator's own body (e.g. via a callback or helper the generator invokes), or re-entering the generator recursively through a function that closes over it.

Common situations: Generator body delegates to a callback that calls gen.return() to 'finish early'; recursive iteration helpers; async-like code that tries to finalize a generator from a listener it started.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/addd4a4be5021c71. Report an issue: GitHub.

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JsGenerator.java:64

    static JsObject result(Object value, boolean done) {
        JsObject r = new JsObject();
        r.putMember("value", value);
        r.putMember("done", done);
        return r;
    }

    Object next(CoreContext ctx, Object value) {
        if (activation.isDone()) {
            return result(Terms.UNDEFINED, true);
        }
        return drive(ctx, ResumeKind.NEXT, value);
    }

    Object returnValue(CoreContext ctx, Object value) {
        if (activation.isDone() || !activation.isStarted()) {
            if (activation.isRunning()) {
                throw JsErrorException.typeError("Generator is already running");
            }
            activation.retire(); // NOT_STARTED: no body code runs
            return result(value, true);
        }
        return drive(ctx, ResumeKind.RETURN, value);
    }

    Object throwValue(CoreContext ctx, Object value) {
        if (activation.isDone() || !activation.isStarted()) {
            if (activation.isRunning()) {
                throw JsErrorException.typeError("Generator is already running");
            }
            activation.retire(); // NOT_STARTED: no body code runs
            ctx.stopAndThrow(value);
            return Terms.UNDEFINED;
        }
        return drive(ctx, ResumeKind.THROW, value);
    }

View on GitHub (pinned to a22eb90246)