{"record":{"id":"19e3cfcc147b368d","repo":"karatelabs/karate","slug":"settimeout-callback-is-not-a-function","errorCode":null,"errorMessage":"setTimeout: callback is not a function","messagePattern":"setTimeout: callback is not a function","errorType":"exception","errorClass":"JsErrorException","httpStatus":null,"severity":"error","filePath":"karate-js/src/main/java/io/karatelabs/js/AsyncSupport.java","lineNumber":742,"sourceCode":"     *  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();\n        AsyncScope.TimerRecord record = new AsyncScope.TimerRecord(scope, id, token);\n        scope.addTimer(record);\n        TimerScheduler timer = scheduler();\n        // the closed-check and the registration are one atomic step under the","sourceCodeStart":724,"sourceCodeEnd":760,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-js/src/main/java/io/karatelabs/js/AsyncSupport.java#L724-L760","documentation":"setTimeout's first argument must be a JsCallable (a function). Any other value — string, number, object, null — is rejected with a TypeError, mirroring the JS spec's requirement that the callback be callable.","triggerScenarios":"setTimeout('someCode', 100) or setTimeout(undefined) / setTimeout(null) / setTimeout(obj.method) where the property is missing — i.e. arg(args,0) does not implement JsCallable.","commonSituations":"Porting browser snippets that pass a string of code (browser-only behavior); passing the result of an optional lookup that came back undefined; a typo making the callback resolve to a non-function.","solutions":["Pass an actual function reference: setTimeout(() => ..., delay).","Check the value with typeof cb === 'function' before scheduling.","If migrating string-based setTimeout, wrap the code in an arrow function."],"exampleFix":"// before\nsetTimeout('doWork()', 100);\n// after\nsetTimeout(() => doWork(), 100);","handlingStrategy":"type-guard","validationCode":"if (typeof callback !== 'function') throw new TypeError('setTimeout callback must be a function');","typeGuard":"function isCallable(v) { return typeof v === 'function'; }","tryCatchPattern":"try { setTimeout(cb, 100); } catch (e) { if (e instanceof TypeError && e.message.includes('not a function')) { /* inspect cb value */ } else throw e; }","preventionTips":["Always pass function expressions, not strings.","Guard optional callbacks: if (typeof maybeCb === 'function') setTimeout(maybeCb, d).","Avoid porting browser string-callback snippets verbatim."],"tags":["javascript","type-mismatch","timers"],"backgroundTag":"type-mismatch","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"}