grafana/k6 · error

unexpected value of type %T

Error message

unexpected value %v of type %T

What it means

The count() path received a non-float64 result from the injected counting script (expected a number returned by value from the evaluation). This is an internal Go/JS contract violation — legitimate DOM counts always arrive as float64 via returnByValue.

Solutions

  1. Upgrade or pin a consistent k6 version
  2. Isolate against a static page to rule out app interference
  3. Work around with page.evaluate(() => document.querySelectorAll(sel).length)
  4. File a k6 issue with the minimal case

Example fix

// workaround
const n = await page.evaluate(() => document.querySelectorAll('.item').length);
Defensive patterns

Strategy: fallback

Try / catch

try {
  const n = await page.locator('.item').count();
} catch (e) {
  if (/unexpected value/.test(String(e))) {
    const n = await page.evaluate(() => document.querySelectorAll('.item').length);
  } else throw e;
}

Prevention

When it happens

Trigger: el.count() or frame-chained counts where evalWithScript returns a string/object/undefined because the injected script was interfered with or the evaluation protocol broke; distinct from selector errors, which fail earlier in NewSelector/waitForSelector.

Common situations: Adversarial pages patching globals used by injected scripts; k6 version mismatch between the generated JS helpers and the binary; not seen in ordinary flows.

Related errors


AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18). Data as JSON: /api/errors/92f542c827d6728b. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/common/element_handle.go:767

	eopts := evalOptions{
		forceCallable: true,
		returnByValue: true,
	}
	result, err := h.evalWithScript(
		apiCtx,
		eopts, fn, parsedSelector,
	)
	if err != nil {
		return 0, err
	}
	switch r := result.(type) {
	case float64:
		if r < float64(math.MinInt32) || r > float64(math.MaxInt32) {
			return 0, fmt.Errorf("value %v out of range for int32 type", r)
		}
		return int(r), nil
	default:
		return 0, fmt.Errorf("unexpected value %v of type %T", r, r)
	}
}

// findFrameNavigationIndex finds the index of the first internal:control=enter-frame directive
func (h *ElementHandle) findFrameNavigationIndex(selector *Selector) int {
	for i, part := range selector.Parts {
		if part.Name == "internal:control" && part.Body == "enter-frame" {
			return i
		}
	}
	return -1
}

// splitSelectorAtFrame splits a selector at the frame navigation boundary
func (h *ElementHandle) splitSelectorAtFrame(selector *Selector, frameIndex int) (*Selector, *Selector) {
	beforeFrame := &Selector{
		Selector: selector.Selector, // Keep original for reference
		Parts:    selector.Parts[:frameIndex],

View on GitHub (pinned to 3fcf5388d7)