grafana/k6 · error
's callback isn't a callable function
Error message
%s's callback isn't a callable function
What it means
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.
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'.
Example fix
// before
const cb = maybeHandler; // undefined
setTimeout(cb, 1000);
// after
if (typeof maybeHandler === 'function') {
setTimeout(maybeHandler, 1000);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof cb !== 'function') {
throw new TypeError('setTimeout requires a function callback');
}
setTimeout(cb, delay); Type guard
function isCallable(v) {
return typeof v === 'function';
} Prevention
- 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).
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- group() does not support async functions as arguments…
- setTimeout requires a function as first argument
- typedArray parameter is required
- typedArray parameter's length is negative
- 104
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-09-20).
Data as JSON: /api/errors/60361083730ba5e1.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/tc55/timers/timers.go:142
// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timer-initialisation-steps
// NOTE: previousId from the specification is always send and it is basically id
//
// Repeated timers must reuse the registration-time metric context when they rearm.
func (e *timers) timerInitialization(
callback sobek.Callable, timeout float64, args []sobek.Value, repeat bool, id uint64,
) {
// skip all the nesting stuff as we do not care about them
if timeout < 0 {
timeout = 0
}
name := setTimeoutName
if repeat {
name = setIntervalName
}
if callback == nil {
common.Throw(e.vu.Runtime(), fmt.Errorf("%s's callback isn't a callable function", name))
}
t := &timer{
id: id,
nextTrigger: time.Now().Add(time.Duration(timeout * float64(time.Millisecond))),
name: name,
}
t.task = func() error {
return e.runTask(t, callback, timeout, args, repeat)
}
e.runAfterTimeout(t)
}
// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout
// Notes: this just takes timers as makes the implementation way easier and we do not currently need
// most of the functionality provided
func (e *timers) runAfterTimeout(t *timer) {
e.timers[t.id] = tView on GitHub (pinned to 3fcf5388d7)