{"record":{"id":"60361083730ba5e1","repo":"grafana/k6","slug":"s-s-callback-isn-t-a-callable-function","errorCode":null,"errorMessage":"%s's callback isn't a callable function","messagePattern":"(.+?)'s callback isn't a callable function","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/tc55/timers/timers.go","lineNumber":142,"sourceCode":"// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timer-initialisation-steps\n// NOTE: previousId from the specification is always send and it is basically id\n//\n// Repeated timers must reuse the registration-time metric context when they rearm.\nfunc (e *timers) timerInitialization(\n\tcallback sobek.Callable, timeout float64, args []sobek.Value, repeat bool, id uint64,\n) {\n\t// skip all the nesting stuff as we do not care about them\n\tif timeout < 0 {\n\t\ttimeout = 0\n\t}\n\n\tname := setTimeoutName\n\tif repeat {\n\t\tname = setIntervalName\n\t}\n\n\tif callback == nil {\n\t\tcommon.Throw(e.vu.Runtime(), fmt.Errorf(\"%s's callback isn't a callable function\", name))\n\t}\n\n\tt := &timer{\n\t\tid:          id,\n\t\tnextTrigger: time.Now().Add(time.Duration(timeout * float64(time.Millisecond))),\n\t\tname:        name,\n\t}\n\tt.task = func() error {\n\t\treturn e.runTask(t, callback, timeout, args, repeat)\n\t}\n\te.runAfterTimeout(t)\n}\n\n// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout\n// Notes: this just takes timers as makes the implementation way easier and we do not currently need\n// most of the functionality provided\nfunc (e *timers) runAfterTimeout(t *timer) {\n\te.timers[t.id] = t","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/grafana/k6/blob/3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee/internal/js/tc55/timers/timers.go#L124-L160","documentation":"Fires during timer initialization when the first argument passed to setTimeout or setInterval exists but is not a callable function value (e.g. a string, number, or object). This is a generic guard at the top of timerInitialization: the callback cannot be invoked as a sobek.Callable (nil or non-callable), so k6 aborts setup of the timer before registering it with the event loop, since there is nothing to invoke when the timer fires.","triggerScenarios":"Calling setTimeout(undefined, 100), setTimeout(null), setTimeout() with no arguments, or passing a non-function (string, object) where a function is expected; also runTask with a nil callback.","commonSituations":"Conditional code that builds the callback but leaves it undefined; typo'd function names (setTimeout(myFuncton, 100) -> undefined variable becomes undefined under non-strict handling); refactoring that removed the handler.","solutions":["Pass an actual function: setTimeout(() => {...}, 100).","Check for typos in the callback identifier so it doesn't resolve to undefined.","Guard the call site: only schedule the timer when typeof cb === 'function'."],"exampleFix":"// before\nconst cb = maybeHandler; // undefined\nsetTimeout(cb, 1000);\n// after\nif (typeof maybeHandler === 'function') {\n  setTimeout(maybeHandler, 1000);\n}","handlingStrategy":"type-guard","validationCode":"if (typeof cb !== 'function') {\n  throw new TypeError('setTimeout requires a function callback');\n}\nsetTimeout(cb, delay);","typeGuard":"function isCallable(v) {\n  return typeof v === 'function';\n}","tryCatchPattern":null,"preventionTips":["Never schedule timers conditionally with an undefined callback; pass a no-op function instead.","Check identifier spelling when passing named functions.","Use default parameters: function schedule(cb = () => {}, delay)."],"tags":["timers","javascript","callback","k6"],"backgroundTag":"missing-required-argument","analyzedSha":"3fcf5388d78cb382f0c0d42ec556a06bfd1b8dee","analyzedAt":"2026-09-20T22:01:45.163Z","contentChangedAt":"2026-09-20T22:01:45.163Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}