grafana/k6 · error

stack too big

Error message

stack too big

What it means

getPreviousRequiringFile() walks up to 1000 captured stack frames looking for the internal require wrapper frame ('(*requireImpl).require-fm') to identify the file that triggered a require (mostly for legacy open() semantics). If the stack reaches 1000 frames without finding it, k6 gives up with 'stack too big' rather than guessing the caller. This is an internal guard, not a normal user error.

Source

Thrown at js/modules/require_impl.go:217

func getPreviousRequiringFile(vu VU) (string, error) {
	rt := vu.Runtime()
	var buf [1000]sobek.StackFrame
	frames := rt.CaptureCallStack(1000, buf[:0])

	for i, frame := range frames[1:] { // first one should be the current require
		// TODO have this precalculated automatically
		if frame.FuncName() == "go.k6.io/k6/v2/internal/js.(*requireImpl).require-fm" {
			// we need to get the one *before* but as we skip the first one the index matches ;)
			result := frames[i].SrcName()
			if result == "file:///-" {
				return vu.InitEnv().CWD.JoinPath("./-").String(), nil
			}
			return result, nil
		}
	}
	// hopefully nobody is calling `require` with 1000 big stack :crossedfingers:
	if len(frames) == 1000 {
		return "", errors.New("stack too big")
	}

	// fallback
	result := frames[len(frames)-1].SrcName()
	if result == "file:///-" {
		return vu.InitEnv().CWD.JoinPath("./-").String(), nil
	}
	return result, nil
}

// sets the provided promise in such way as to ignore falures
// this is mostly needed as failures are handled separately and we do not want those to lead to stopping the event loop
func promisesThenIgnore(rt *sobek.Runtime, promise *sobek.Promise) {
	call, _ := sobek.AssertFunction(rt.ToValue(promise).ToObject(rt).Get("then"))
	handler := rt.ToValue(func(_ sobek.Value) {})
	_, _ = call(rt.ToValue(promise), handler, handler)
}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Hoist the require()/open() call to module top level instead of calling it deep in recursion
  2. Reduce recursion depth (convert to iteration or memoize) if the call site must stay nested
  3. If it reproduces with a reasonably shallow stack, report it as a k6 bug with the script

Example fix

// before (deep inside recursion)
function walk(n) { if (n === 0) { data = open('./f.json'); return; } walk(n - 1); }

// after (top level)
const data = open('./f.json');
function walk(n) { /* uses the preloaded data */ }
Defensive patterns

Strategy: try-catch

Try / catch

// in JS: hoist open()/require() to top level so this internal guard never triggers;
// in Go callers of getPreviousRequiringFile, treat the error as non-fatal and fall back to a known file.

Prevention

When it happens

Trigger: Calling require()/open() from inside ~1000-deep recursion or a very long call chain, so the wrapper frame falls outside the 1000-frame window captured by rt.CaptureCallStack(1000, ...).

Common situations: Deeply recursive helper functions that eventually require() or open() a file; machine-generated scripts with enormous call chains; bundler output that inlines huge module trees. Extremely rare in practice.

Related errors


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