karatelabs/karate · error · JsErrorException

yield is only valid inside a generator function

Error message

yield is only valid inside a generator function

What it means

Thrown as a syntax error when `yield` (or `yield*`) is evaluated while no GeneratorActivation is current. `yield` is only meaningful inside a generator function's executing frame; outside one the engine cannot suspend and resume the evaluation.

Solutions

  1. Declare the containing function as a generator: `function* gen() { yield x; }`.
  2. Consume the generator via `it.next()` / iteration instead of calling it directly.
  3. Replace `yield` with a plain return if no suspension/resume semantics are needed.

Example fix

// before
function produce() { yield 1; }
// after
function* produce() { yield 1; }
var it = produce();
Defensive patterns

Strategy: validation

Validate before calling

if (!/^function\s*\*/.test(String(fn))) throw new Error('yield requires a generator function');

Type guard

function isGeneratorFn(f) { return typeof f === 'function' && /^\s*function\s*\*/.test(String(f)); }

Try / catch

try { step(); } catch (e) { if (String(e).includes('yield is only valid')) { /* convert to generator or return */ } }

Prevention

When it happens

Trigger: Using `yield` in a plain function, in top-level script, or calling the generator's inner function object directly rather than through the generator protocol (next()).

Common situations: Copy-pasting generator bodies into regular functions; forgetting `function*` syntax when declaring the generator; invoking yield-containing code from a callback.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/Interpreter.java:2880

            return value;
        }
        try {
            return AsyncSupport.await(value, context);
        } catch (AsyncSupport.AwaitRejection e) {
            context.stopAndThrow(e.reason);
            return Terms.UNDEFINED;
        }
    }

    /**
     * {@code yield x} / {@code yield* iterable}. Node shape:
     * [yield-token, STAR?, EXPR?]. Runs only on a generator's vthread —
     * {@link GeneratorActivation#current()} is the brand.
     */
    private static Object evalYieldExpr(Node node, CoreContext context) {
        GeneratorActivation act = GeneratorActivation.current();
        if (act == null) {
            throw JsErrorException.syntaxError("yield is only valid inside a generator function");
        }
        boolean star = node.size() > 1 && node.get(1).isToken()
                && node.get(1).token.type == TokenType.STAR;
        Node operandNode = null;
        if (star) {
            operandNode = node.get(2);
        } else if (node.size() > 1) {
            operandNode = node.get(1);
        }
        Object operand = operandNode == null ? Terms.UNDEFINED : eval(operandNode, context);
        if (context.isStopped()) {
            return operand;
        }
        if (star) {
            return evalYieldStar(operand, context, act);
        }
        return applyResume(act.yieldAndReceive(operand), context);
    }

View on GitHub (pinned to a22eb90246)