grafana/k6 · error
setTimeout requires a function as first argument
Error message
setTimeout requires a function as first argument
What it means
k6/experimental exposes a timer API compatible in spirit with window.setTimeout, but implemented on the sobek runtime with a Go signature of (f sobek.Callable, t float64). If the first argument cannot be bound to a callable (or is nil after binding), the module throws immediately - unlike browsers, it does not accept a string of code to eval.
Solutions
- Pass an actual function reference: setTimeout(() => console.log('hi'), 100).
- Check the identifier exists: a typo'd function name evaluates to undefined at the call site and hits the nil-callable path.
- Do not port string-callback code from browsers; rewrite it as arrow functions.
Example fix
// before
setTimeout('console.log("done")', 1000); // throws
// after
setTimeout(() => console.log('done'), 1000); Defensive patterns
Strategy: type-guard
Validate before calling
function safeSetTimeout(cb, ms, ...args) {
if (typeof cb !== 'function') {
throw new TypeError(`setTimeout callback must be a function, got ${typeof cb}`);
}
return setTimeout(cb, ms);
} Type guard
const isFunction = (v) => typeof v === 'function';
Prevention
- Never port string-form setTimeout from browser code.
- Lint for setTimeout('...') string literals in k6 projects.
When it happens
Trigger: setTimeout('console.log(1)', 100) passing a string like the legacy browser API; setTimeout(123, 100); or calling setTimeout with no arguments so the callable parameter is nil.
Common situations: Copy-pasting browser setTimeout snippets that use string callbacks; renaming a callback that ends up undefined (typo) so the value passed is nil; assuming eval-style timers exist in k6.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- must be a number
- a function is expected as the second argument of…
- cannot be null or undefined
- csv Parser constructor must be called in the init context
- height must be a number, got
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/a2eed4dd28bf9175.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/experimental/experimental.go:48
}
// New returns a new RootModule.
func New() *RootModule {
return &RootModule{}
}
// Exports returns the exports of the experimental module
func (mi *ModuleInstance) Exports() modules.Exports {
return modules.Exports{
Named: map[string]any{
"setTimeout": mi.setTimeout,
},
}
}
func (mi *ModuleInstance) setTimeout(f sobek.Callable, t float64) {
if f == nil {
common.Throw(mi.vu.Runtime(), errors.New("setTimeout requires a function as first argument"))
}
// TODO maybe really return something to use with `clearTimeout
// TODO support arguments ... maybe
runOnLoop := mi.vu.RegisterCallback()
go func() {
timer := time.NewTimer(time.Duration(t * float64(time.Millisecond)))
select {
case <-timer.C:
runOnLoop(func() error {
_, err := f(sobek.Undefined())
return err
})
case <-mi.vu.Context().Done():
// TODO log something?
timer.Stop()
runOnLoop(func() error { return nil })
}View on GitHub (pinned to 01ffac6f24)