{"record":{"id":"a2b79a9abf7be851","repo":"karatelabs/karate","slug":"settimeout-requires-an-active-evaluation","errorCode":null,"errorMessage":"setTimeout requires an active evaluation","messagePattern":"setTimeout requires an active evaluation","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/AsyncSupport.java","lineNumber":738,"sourceCode":"        return scheduler;\n    }\n\n    /** Owner resolution is from the call's own context, validated against the\n     *  thread's current engine — scheduling without a definite engine is an\n     *  error, not a guess. */\n    private static Engine timerEngine(Context context) {\n        Engine engine = context == null ? null : context.getEngine();\n        if (engine == null || engine != Engine.current()) {\n            throw JsErrorException.typeError(\"setTimeout: no engine is executing on this thread\");\n        }\n        return engine;\n    }\n\n    static Object setTimeout(Context context, Object[] args) {\n        Engine engine = timerEngine(context);\n        AsyncScope scope = engine.currentScope();\n        if (scope == null) {\n            throw JsErrorException.typeError(\"setTimeout requires an active evaluation\");\n        }\n        Object callback = arg(args, 0);\n        if (!(callback instanceof JsCallable target)) {\n            throw JsErrorException.typeError(\"setTimeout: callback is not a function\");\n        }\n        long delay = coerceDelay(arg(args, 1));\n        Object[] extra = args.length > 2 ? Arrays.copyOfRange(args, 2, args.length) : EMPTY_ARGS;\n        if (KarateLifecycle.phase() != KarateLifecycle.Phase.RUNNING) {\n            // refuse before a token is acquired — scheduling is about to be\n            // rejected anyway, and an unbacked token would strand the drain\n            throw new EngineInterruptedException(\"setTimeout: karate is shutting down\");\n        }\n        AsyncToken token = scope.acquire(\"timer\");\n        if (token == null) {\n            throw new EngineInterruptedException();\n        }\n        AsyncActivation.anyAsync = true;\n        int id = scope.nextTimerId();","sourceCodeStart":720,"sourceCodeEnd":756,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/AsyncSupport.java#L720-L756","documentation":"setTimeout requires not only a live engine on the thread but an active AsyncScope evaluation. The scope is what tracks pending timers and drives the drain loop; with no scope in progress there is nothing to attach the timer to, so the call is rejected with a TypeError.","triggerScenarios":"Calling setTimeout from engine code executing outside an async evaluation — e.g. a synchronous top-level eval where no AsyncScope was pushed, or after the async scope completed.","commonSituations":"Using setTimeout in a plain synchronous JS evaluation (no await/async root); calling it during host-driven evaluation that didn't open an async scope; timers scheduled after the async block already returned.","solutions":["Schedule timers only from within an async evaluation (e.g. inside an async function invoked through the engine's async path).","If you need delayed work in sync code, perform it on the Java side instead of via setTimeout.","Ensure the engine's currentScope() is active — don't defer setTimeout calls past the end of the evaluation."],"exampleFix":"// before: sync eval\nevalRaw(\"setTimeout(cb, 50)\"); // throws\n// after: async evaluation\nawait engine.evalRaw(\"(async () => { await delay(50); cb(); })()\");","handlingStrategy":"validation","validationCode":"if (engine.currentScope() == null) throw new IllegalStateException(\"setTimeout needs an active async evaluation\");","typeGuard":null,"tryCatchPattern":"try { engine.evalRaw(\"setTimeout(cb, 50)\"); } catch (JsErrorException e) { if (e.getMessage().equals(\"setTimeout requires an active evaluation\")) { /* do the delayed work in Java */ } else throw e; }","preventionTips":["Use setTimeout only inside async evaluations (async functions / async blocks).","Don't defer setTimeout past the end of the evaluation that owns the scope.","For synchronous scripts, implement delays on the Java side."],"tags":["javascript","async","timers"],"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"}