grafana/k6 · error

setTimeout requires a function as first argument

Error message

setTimeout requires a function as first argument

What it means

k6/experimental's setTimeout only supports a callable as its first argument; sobek binds the parameter as sobek.Callable, and any non-function value (including the browser-style string-eval form) binds as nil, which this guard rejects. Argument passing and clearTimeout are not supported yet (marked TODO in the source).

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 93accf6570)

Solutions

  1. Pass a function reference: setTimeout(fn, 100)
  2. For arguments, wrap in a closure: setTimeout(() => fn(arg1, arg2), 100)
  3. If the delay value comes from config, ensure the function slot is a real function, not a serialized string

Example fix

// before
setTimeout(doWork('x'), 100);

// after
setTimeout(() => doWork('x'), 100);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof callback !== 'function') throw new TypeError('setTimeout callback must be a function');
setTimeout(callback, delayMs);

Type guard

/** @param {unknown} v @returns {v is Function} */
const isCallable = (v) => typeof v === 'function';

if (!isCallable(maybeFn)) throw new TypeError(`expected function, got ${typeof maybeFn}`);

Prevention

When it happens

Trigger: setTimeout('console.log(1)', 100) using the browser string form; passing undefined or a non-function variable; passing the result of calling the function -- setTimeout(fn(), 100) -- instead of the reference setTimeout(fn, 100).

Common situations: Copy-pasting browser or Node.js timer code into a k6 script; passing extra arguments expecting them to be forwarded to the callback (not supported); timers configured from external JSON config strings.

Understand the failure class

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/a2eed4dd28bf9175. Report an issue: GitHub.